ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/runtime/nongui/ibxscript.pas
(Generate patch)

Comparing ibx/trunk/runtime/nongui/ibxscript.pas (file contents):
Revision 229 by tony, Tue Apr 10 13:32:36 2018 UTC vs.
Revision 380 by tony, Mon Jan 10 10:13:17 2022 UTC

# Line 31 | Line 31 | unit ibxscript;
31  
32   interface
33  
34 < uses Classes, IBDatabase,  IBSQL, IB, IBDataOutput;
35 <
36 < const
37 <  ibx_blob = 'IBX_BLOB';
38 <  ibx_array = 'IBX_ARRAY';
39 <
40 <  BlobLineLength = 40;
41 <
42 <  DefaultTerminator = ';';
43 <
44 <  {Non-character symbols}
45 <  sqNone                 = #0;
46 <  sqEnd                  = #1;
47 <  sqBegin                = #2;
48 <  sqString               = #3;
49 <  sqComment              = #4;
50 <  sqCase                 = #5;
51 <  sqDeclare              = #6;
52 <  sqCommentLine          = #7;
53 <  sqEOL                  = #8;
54 <  sqTab                  = #9;
55 <  sqTerminator           = #10;
56 <  sqEOF                  = #11;
57 <  sqTag                  = #12;
58 <  sqEndTag               = #13;
59 <  sqQuotedString         = #14;
60 <  sqDoubleQuotedString   = #15;
34 > uses Classes, IBDatabase,  IBSQL, IB, IBDataOutput, IBUtils;
35  
36   type
63  TSQLSymbol = char;
64
65  TSQLStates =  (stInit, stError, stInSQL, stNested,  stInDeclaration);
66
67  TXMLStates =  (stInTag,stAttribute,stAttributeValue,stQuotedAttributeValue,
68                 stTagged,stEndTag);
69
70  TXMLTag    =   (xtNone,xtBlob,xtArray,xtElt);
37  
38    TOnNextLine = procedure(Sender: TObject; Line: string) of object;
39    TOnProgressEvent = procedure (Sender: TObject; Reset: boolean; value: integer) of object;
40  
41 <  TXMLTagDef = record
76 <    XMLTag: TXMLTag;
77 <    TagValue: string;
78 <  end;
79 <
80 < const
81 <  XMLTagDefs: array [0..2] of TXMLTagDef = (
82 <    (XMLTag: xtBlob;   TagValue: 'blob'),
83 <    (XMLTag: xtArray;  TagValue: 'array'),
84 <    (XMLTag: xtElt;    TagValue: 'elt')
85 <    );
41 >  { TSQLXMLReader }
42  
43 < type
43 >  TSQLXMLReader = class(TSQLTokeniser)
44 >  private
45 >    type
46 >      TXMLStates =  (stNoXML, stInTag,stInTagBody,
47 >                     stAttribute,stAttributeValue,stQuotedAttributeValue,
48 >                     stInEndTag, stInEndTagBody,
49 >                     stXMLData);
50 >
51 >      TXMLTag    =   (xtNone,xtBlob,xtArray,xtElt);
52 >
53 >      TXMLTagDef = record
54 >        XMLTag: TXMLTag;
55 >        TagValue: string;
56 >      end;
57 >
58 >    const
59 >      XMLTagDefs: array [xtBlob..xtElt] of TXMLTagDef = (
60 >        (XMLTag: xtBlob;   TagValue: 'blob'),
61 >        (XMLTag: xtArray;  TagValue: 'array'),
62 >        (XMLTag: xtElt;    TagValue: 'elt')
63 >        );
64 >      MaxXMLTags = 20;
65 >      BlobLineLength = 40;
66  
67 <  { TSymbolStream }
67 >  public
68 >    const
69 >      ibx_blob = 'IBX_BLOB';
70 >      ibx_array = 'IBX_ARRAY';
71 >
72 >    type
73 >      TBlobData = record
74 >        BlobIntf: IBlob;
75 >        SubType: cardinal;
76 >      end;
77 >
78 >      TArrayData = record
79 >        ArrayIntf: IArray;
80 >        SQLType: cardinal;
81 >        relationName: string;
82 >        columnName: string;
83 >        dim: cardinal;
84 >        Size: cardinal;
85 >        Scale: integer;
86 >        CharSet: string;
87 >        bounds: TArrayBounds;
88 >        CurrentRow: integer;
89 >        Index: array of integer;
90 >      end;
91 >
92 >   private
93 >     FDatabase: TIBDatabase;
94 >     FOnProgressEvent: TOnProgressEvent;
95 >     FTransaction: TIBTransaction;
96 >     FXMLState: TXMLStates;
97 >     FXMLTagStack: array [1..MaxXMLTags] of TXMLTag;
98 >     FXMLTagIndex: integer;
99 >     FAttributeName: string;
100 >     FXMLData: string;
101 >     FBlobData: array of TBlobData;
102 >     FCurrentBlob: integer;
103 >     FBlobBuffer: PChar;
104 >     FArrayData: array of TArrayData;
105 >     FCurrentArray: integer;
106 >     FXMLString: string;
107 >     function FindTag(tag: string; var xmlTag: TXMLTag): boolean;
108 >     function GetArrayData(index: integer): TArrayData;
109 >     function GetArrayDataCount: integer;
110 >     function GetBlobData(index: integer): TBlobData;
111 >     function GetBlobDataCount: integer;
112 >     function GetTagName(xmltag: TXMLTag): string;
113 >     procedure ProcessAttributeValue(attrValue: string);
114 >     procedure ProcessBoundsList(boundsList: string);
115 >     procedure ProcessTagValue(tagValue: string);
116 >     procedure XMLTagInit(xmltag: TXMLTag);
117 >     function XMLTagEnd(var xmltag: TXMLTag): boolean;
118 >     procedure XMLTagEnter;
119 >   protected
120 >     function GetErrorPrefix: string; virtual; abstract;
121 >     function TokenFound(var token: TSQLTokens): boolean; override;
122 >     procedure Reset; override;
123 >     procedure ShowError(msg: string; params: array of const); virtual; overload;
124 >     procedure ShowError(msg: string); overload;
125 >   public
126 >     constructor Create;
127 >     procedure FreeDataObjects;
128 >     class function FormatBlob(Field: ISQLData): string;
129 >     class function FormatArray(Database: TIBDatabase; ar: IArray): string;
130 >     property BlobData[index: integer]: TBlobData read GetBlobData;
131 >     property BlobDataCount: integer read GetBlobDataCount;
132 >     property ArrayData[index: integer]: TArrayData read GetArrayData;
133 >     property ArrayDataCount: integer read GetArrayDataCount;
134 >     property Database: TIBDatabase read FDatabase write FDatabase;
135 >     property Transaction: TIBTransaction read FTransaction write FTransaction;
136 >     property OnProgressEvent: TOnProgressEvent read FOnProgressEvent write FOnProgressEvent; {Progress Bar Support}
137 >  end;
138  
139 <  {A simple lookahead one parser to process a text stream as a stream of symbols.
92 <   This is an abstract object, subclassed for different sources.}
139 >  { TSQLStatementReader }
140  
141 <  TSymbolStream = class
141 >  TSQLStatementReader = class(TSQLXMLReader)
142    private
143 <    FNextSymbol: TSQLSymbol;
143 >    type
144 >      TSQLState = (stDefault, stInStmt, stInBlock, stInArrayDim, stInDeclare);
145 >  private
146 >    FHasBegin: boolean;
147      FOnNextLine: TOnNextLine;
98    FOnProgressEvent: TOnProgressEvent;
148      FTerminator: char;
100    FLastChar: char;
101    FIndex: integer;
102    FLine: string;
103    FString: string;
104    FXMLTag: TXMLTag;
105    FXMLMode: integer;
149    protected
150 <    FNextStatement: boolean;
108 <    function GetErrorPrefix: string; virtual; abstract;
109 <    function GetNextSymbol(C: char): TSQLSymbol;
110 <    function FindTag(tag: string; var xmlTag: TXMLTag): boolean;
111 <    function GetNextLine(var Line: string):boolean; virtual; abstract;
150 >    procedure EchoNextLine(aLine: string);
151    public
152      constructor Create;
153 <    procedure ShowError(msg: string; params: array of const);
154 <    function GetSymbol: TSQLSymbol; virtual;
155 <    procedure NextStatement;
117 <    property SymbolValue: string read FString;
118 <    property Terminator: char read FTerminator write FTerminator;
119 <    property XMLTag: TXMLTag read FXMLTag;
153 >    function GetNextStatement(var stmt: string) : boolean; virtual;
154 >    property HasBegin: boolean read FHasBegin;
155 >    property Terminator: char read FTerminator write FTerminator default DefaultTerminator;
156      property OnNextLine: TOnNextLine read FOnNextLine write FOnNextLine;
121    property OnProgressEvent: TOnProgressEvent read FOnProgressEvent write FOnProgressEvent; {Progress Bar Support}
157    end;
158  
124  { TBatchSymbolStream }
159  
160 <  {This symbol stream supports non-interactive parsing of a text file, stream or
160 >  { TBatchSQLStatementReader }
161 >
162 >  {This SQL Reader supports non-interactive parsing of a text file, stream or
163     lines of text.}
164  
165 <  TBatchSymbolStream = class(TSymbolStream)
165 >  TBatchSQLStatementReader = class(TSQLStatementReader)
166    private
167 <    FLines: TStrings;
167 >    FInStream: TStream;
168 >    FOwnsInStream: boolean;
169      FLineIndex: integer;
170 +    FIndex: integer;
171 +    FCurLine: string;
172    protected
173 +    function GetChar: char; override;
174      function GetErrorPrefix: string; override;
135    function GetNextLine(var Line: string):boolean; override;
175    public
176 <    constructor Create;
138 <    destructor Destroy; override;
176 >    procedure Reset; override;
177      procedure SetStreamSource(Lines: TStrings); overload;
178      procedure SetStreamSource(S: TStream); overload;
179      procedure SetStreamSource(FileName: string); overload;
180 +    procedure SetStringStreamSource(S: string);
181    end;
182  
183 <  { TInteractiveSymbolStream }
183 >  { TInteractiveSQLStatementReader }
184  
185 <  {This symbol stream supports interactive parsing of commands and
185 >  {This SQL reader supports interactive parsing of commands and
186     SQL statements entered at a console}
187  
188 <  TInteractiveSymbolStream = class(TSymbolStream)
188 >  TInteractiveSQLStatementReader = class(TSQLStatementReader)
189    private
190      FPrompt: string;
191      FContinuePrompt: string;
192      FTerminated: boolean;
193 +    FLine: string;
194 +    FLineIndex: integer;
195 +    FNextStatement: boolean;
196 +    function GetNextLine(var Line: string):boolean;
197    protected
198 +    function GetChar: char; override;
199      function GetErrorPrefix: string; override;
156    function GetNextLine(var Line: string):boolean; override;
200    public
201      constructor Create(aPrompt: string='SQL>'; aContinue: string = 'CON>');
202 <    function GetSymbol: TSQLSymbol; override;
202 >    function GetNextStatement(var stmt: string) : boolean; override;
203      property Terminated: boolean read FTerminated write FTerminated;
204    end;
205  
163  TBlobData = record
164    BlobIntf: IBlob;
165    SubType: cardinal;
166  end;
167
168  TArrayData = record
169    ArrayIntf: IArray;
170    SQLType: cardinal;
171    relationName: string;
172    columnName: string;
173    dim: cardinal;
174    Size: cardinal;
175    Scale: integer;
176    CharSet: string;
177    bounds: TArrayBounds;
178    CurrentRow: integer;
179    Index: array of integer;
180  end;
181
182  { TIBXMLProcessor }
183
184  {This is a simple XML parser that parses the output of a symbol stream as XML
185   structured data, recognising tags, attributes and data. The tags are given in
186   the table XMLTagDefs. The BlobData and ArrayData properties return blob and
187   array data decoded from the XML stream.}
188
189  TIBXMLProcessor = class
190  private
191    FDatabase: TIBDatabase;
192    FSymbolStream: TSymbolStream;
193    FState: TXMLStates;
194    FTransaction: TIBTransaction;
195    FXMLTagStack: array [1..20] of TXMLTag;
196    FXMLTagIndex: integer;
197    FAttributeName: string;
198    FBlobData: array of TBlobData;
199    FCurrentBlob: integer;
200    FArrayData: array of TArrayData;
201    FCurrentArray: integer;
202    FBlobBuffer: PChar;
203    procedure EndXMLTag(xmltag: TXMLTag);
204    procedure EnterTag;
205    function GetArrayData(index: integer): TArrayData;
206    function GetArrayDataCount: integer;
207    function GetBlobData(index: integer): TBlobData;
208    function GetBlobDataCount: integer;
209    procedure ProcessTagValue(tagValue: string);
210    procedure StartXMLTag(xmltag: TXMLTag);
211    procedure ProcessAttributeValue(attrValue: string);
212    procedure ProcessBoundsList(boundsList: string);
213  public
214    constructor Create;
215    destructor Destroy; override;
216    function AnalyseXML(SymbolStream: TSymbolStream): string;
217    procedure NextStatement;
218    class function FormatBlob(Field: ISQLData): string;
219    class function FormatArray(Database: TIBDatabase; ar: IArray): string;
220    property BlobData[index: integer]: TBlobData read GetBlobData;
221    property BlobDataCount: integer read GetBlobDataCount;
222    property ArrayData[index: integer]: TArrayData read GetArrayData;
223    property ArrayDataCount: integer read GetArrayDataCount;
224    property Database: TIBDatabase read FDatabase write FDatabase;
225    property Transaction: TIBTransaction read FTransaction write FTransaction;
226  end;
227
228  { TIBSQLProcessor }
229
230  {This parses a symbol stream into SQL statements. If embedded XML is found then
231   this is processed by the supplied XMLProcessor. The HasBegin property provides
232   a simple way to recognised stored procedure DDL, and "Execute As" statements.}
233
234  TIBSQLProcessor = class
235  private
236    FSQLText: string;
237    FState: TSQLStates;
238    FStack: array [0..16] of TSQLStates;
239    FStackindex: integer;
240    FHasBegin: boolean;
241    FInCase: boolean;
242    FNested: integer;
243    FXMLProcessor: TIBXMLProcessor;
244    FSymbolStream: TSymbolStream;
245    procedure AddToSQL(const Symbol: string);
246    procedure SetState(AState: TSQLStates);
247    function PopState: TSQLStates;
248  public
249    constructor Create(XMLProcessor: TIBXMLProcessor);
250    function GetNextStatement(SymbolStream: TSymbolStream; var stmt: string) : boolean;
251    property HasBegin: boolean read FHasBegin;
252  end;
253
206    TGetParamValue = procedure(Sender: TObject; ParamName: string; var BlobID: TISC_QUAD) of object;
207    TLogEvent = procedure(Sender: TObject; Msg: string) of Object;
208    TOnSelectSQL = procedure (Sender: TObject; SQLText: string) of object;
# Line 272 | Line 224 | type
224    TCustomIBXScript = class(TComponent)
225    private
226      FEcho: boolean;
227 <    FIBXMLProcessor: TIBXMLProcessor;
276 <    FIBSQLProcessor: TIBSQLProcessor;
227 >    FSQLReader: TSQLStatementReader;
228      FDatabase: TIBDatabase;
229      FDataOutputFormatter: TIBCustomDataOutput;
230      FIgnoreCreateDatabase: boolean;
# Line 302 | Line 253 | type
253      procedure SetShowPerformanceStats(AValue: boolean);
254      procedure SetTransaction(AValue: TIBTransaction);
255    protected
305    FSymbolStream: TSymbolStream;
256      procedure Add2Log(const Msg: string; IsError: boolean=true); virtual;
257      procedure ExecSQL(stmt: string);
258      procedure EchoNextLine(Sender: TObject; Line: string);
259      procedure Notification(AComponent: TComponent; Operation: TOperation); override;
260      function ProcessStatement(stmt: string): boolean; virtual;
261      function ProcessStream: boolean;
262 +    procedure SetSQLStatementReader(SQLStatementReader: TSQLStatementReader);
263    public
264      constructor Create(aOwner: TComponent); override;
265      destructor Destroy; override;
266      procedure DefaultSelectSQLHandler(aSQLText: string);
267 +    property SQLStatementReader: TSQLStatementReader read FSQLReader;
268    published
269      property Database: TIBDatabase read FDatabase write SetDatabase;
270      property DataOutputFormatter: TIBCustomDataOutput read FDataOutputFormatter
# Line 431 | Line 383 | implementation
383   uses Sysutils, RegExpr;
384  
385   resourcestring
434  sTerminatorUnknownState = 'Statement Terminator in unexpected state (%d)';
386    sNoSelectSQL = 'Select SQL Statements are not supported';
436  sStackUnderflow = 'Stack Underflow';
387    sNoParamQueries =  'Parameterised Queries are not supported';
438  sStackOverFlow = 'Stack Overflow';
388    sResolveQueryParam =  'Resolving Query Parameter: %s';
389    sXMLStackUnderflow = 'XML Stack Underflow';
390    sInvalidEndTag = 'XML End Tag Mismatch - %s';
391 +  sBadEndTagClosing = 'XML End Tag incorrectly closed';
392    sXMLStackOverFlow = 'XML Stack Overflow';
443  sErrorState = 'Entered Error State';
444  sXMLError = 'Invalid XML (%c)';
393    sXMLAttributeError = 'Unexpected attribute - "%s" = "%s"';
394    sInvalidBoundsList = 'Invalid array bounds list - "%s"';
395    sBinaryBlockMustbeEven = 'Binary block must have an even number of characters';
# Line 450 | Line 398 | resourcestring
398    sArrayIndexError = 'Array Index Error (%d)';
399    sBlobIndexError = 'Blob Index Error (%d)';
400    sStatementError = 'Error processing SQL statement: %s %s - for statement "%s"';
401 + //  sNotInArray = 'elt tag found but not in an XML array tag';
402 +  sNoDatabase = 'Missing database for xml tag import';
403 +  sNoTransaction = 'Missing transaction for xml tag import';
404  
405   function StringToHex(octetString: string; MaxLineLength: integer): string; overload;
406  
# Line 491 | Line 442 | begin
442      TextOut.Add(StringToHex(octetString,MaxLineLength));
443   end;
444  
445 + { TSQLStatementReader }
446 +
447 + procedure TSQLStatementReader.EchoNextLine(aLine: string);
448 + begin
449 +  if assigned(FOnNextLine) then
450 +    OnNextLine(self,aLine);
451 + end;
452 +
453 + constructor TSQLStatementReader.Create;
454 + begin
455 +  inherited Create;
456 +  Terminator := DefaultTerminator;
457 + end;
458 +
459 + function TSQLStatementReader.GetNextStatement(var stmt: string): boolean;
460 + var State: TSQLState;
461 +    Nested: integer;
462 +    token: TSQLTokens;
463 +    EndOfStatement: boolean;
464 + begin
465 +  FHasBegin := false;
466 +  Result := false;
467 +  EndOfStatement := false;
468 +  Nested := 0;
469 +  stmt := '';
470 +  State := stDefault;
471 +  while not EOF and not EndOfStatement do
472 +  begin
473 +    token := GetNextToken;
474 + //    writeln(token,' ',TokenText,' ',Terminator);
475 +    case State of
476 +    stDefault:
477 +      {ignore everything before a reserved word}
478 +      if (token <= high(TSQLReservedWords)) or (token = sqltIdentifier) then
479 +        begin
480 +          State := stInStmt;
481 +          stmt += TokenText;
482 +        end;
483 +
484 +    stInStmt:
485 +       begin
486 +        case token of
487 +          sqltBegin:
488 +          begin
489 +            FHasBegin := true;
490 +            State := stInBlock;
491 +            Nested := 1;
492 +            stmt += TokenText;
493 +          end;
494 +
495 +          sqltDeclare:
496 +            begin
497 +              State := stInDeclare;
498 +              stmt += TokenText;
499 +            end;
500 +
501 +          sqltOpenSquareBracket:
502 +             begin
503 +               State := stInArrayDim;
504 +               stmt += TokenText;
505 +             end;
506 +
507 +          sqltComment:
508 +            stmt += '/*' + TokenText + '*/';
509 +
510 +          sqltCommentLine:
511 +            stmt += '/*' + TokenText + ' */' + LineEnding;
512 +
513 +          sqltQuotedString:
514 +            stmt += '''' + SQLSafeString(TokenText) + '''';
515 +
516 +          sqltIdentifierInDoubleQuotes:
517 +            stmt += '"' + TokenText + '"';
518 +
519 +          sqltEOL:
520 +            stmt += LineEnding;
521 +
522 +          else
523 +            begin
524 +              if (tokentext = Terminator) and (Nested = 0) then
525 +              begin
526 +                EndOfStatement := true;
527 +                State := stDefault;
528 +              end
529 +              else
530 +                stmt += TokenText;
531 +            end;
532 +          end;
533 +        end;
534 +
535 +    {ignore begin..end blocks for Terminator detection }
536 +
537 +    stInBlock:
538 +      begin
539 +        case token of
540 +        sqltBegin:
541 +          begin
542 +            Inc(Nested);
543 +            stmt += TokenText;
544 +          end;
545 +
546 +        sqltEnd:
547 +          begin
548 +            Dec(Nested);
549 +            stmt += TokenText;
550 +            if Nested = 0 then
551 +            begin
552 +              State := stDefault;
553 +              EndOfStatement := true;
554 +            end;
555 +          end;
556 +
557 +        sqltCase:
558 +          {case constructs can appear within select statement in nested blocks.
559 +           We need to match the case constructs END token in order to parse the
560 +           block correctly. This is a simple parser and the only objective is
561 +           to determine the correct end of block. We therefore do not check to
562 +           ensure that the next end properly matches the case. The CASE is thus
563 +           treated the same as BEGIN. The Firebird SQL Parser will flag any errors
564 +           due to mismatched CASE/BEGIN END}
565 +          begin
566 +            Inc(Nested);
567 +            stmt += TokenText;
568 +          end;
569 +
570 +        sqltComment:
571 +          stmt += '/*' + TokenText + '*/';
572 +
573 +        sqltCommentLine:
574 +          stmt += '/* ' + TokenText + ' */' + LineEnding;
575 +
576 +        sqltQuotedString:
577 +          stmt += '''' + SQLSafeString(TokenText) + '''';
578 +
579 +        sqltIdentifierInDoubleQuotes:
580 +          stmt += '"' + TokenText + '"';
581 +
582 +        sqltEOL:
583 +          stmt += LineEnding;
584 +
585 +        else
586 +          stmt += TokenText;
587 +        end;
588 +      end;
589 +
590 +      {ignore array dimensions for Terminator detection }
591 +
592 +    stInArrayDim:
593 +      begin
594 +        case token of
595 +
596 +        sqltComment:
597 +          stmt += '/*' + TokenText + '*/';
598 +
599 +        sqltCommentLine:
600 +          stmt += '/* ' + TokenText + ' */' + LineEnding;
601 +
602 +        sqltCloseSquareBracket:
603 +        begin
604 +          stmt += TokenText;
605 +          State := stInStmt;
606 +        end;
607 +
608 +        sqltEOL:
609 +          stmt += LineEnding;
610 +
611 +        else
612 +          stmt += TokenText;
613 +        end;
614 +      end;
615 +
616 +    {ignore Declare statement for terminator - semi-colon terminates declaration}
617 +
618 +    stInDeclare:
619 +      begin
620 +        case token of
621 +
622 +        sqltComment:
623 +          stmt += '/*' + TokenText + '*/';
624 +
625 +        sqltCommentLine:
626 +          stmt += '/* ' + TokenText + ' */' + LineEnding;
627 +
628 +        sqltQuotedString:
629 +          stmt += '''' + SQLSafeString(TokenText) + '''';  {exists some DECLARE with cursor having SELECT ...\... rc.rdb$constraint_type = 'PRIMARY KEY');}
630 +
631 +        sqltSemiColon:
632 +          begin
633 +            State := stInStmt;
634 +            stmt += TokenText;
635 +          end;
636 +
637 +        sqltEOL:
638 +          stmt += LineEnding;
639 +
640 +        else
641 +          stmt += TokenText;
642 +        end;
643 +      end;
644 +    end;
645 +  end;
646 +  Result := stmt <> '';
647 + end;
648 +
649 + { TSQLXMLReader }
650 +
651 + function TSQLXMLReader.FindTag(tag: string; var xmlTag: TXMLTag): boolean;
652 + var i: TXMLTag;
653 + begin
654 +  Result := false;
655 +  for i := xtBlob to xtElt do
656 +    if XMLTagDefs[i].TagValue = tag then
657 +    begin
658 +      xmlTag := XMLTagDefs[i].XMLTag;
659 +      Result := true;
660 +      break;
661 +    end;
662 + end;
663 +
664 + function TSQLXMLReader.GetArrayData(index: integer): TArrayData;
665 + begin
666 +  if (index < 0) or (index > ArrayDataCount) then
667 +    ShowError(sArrayIndexError,[index]);
668 +  Result := FArrayData[index];
669 + end;
670 +
671 + function TSQLXMLReader.GetArrayDataCount: integer;
672 + begin
673 +  Result := Length(FArrayData);
674 + end;
675 +
676 + function TSQLXMLReader.GetBlobData(index: integer): TBlobData;
677 + begin
678 +  if (index < 0) or (index > BlobDataCount) then
679 +    ShowError(sBlobIndexError,[index]);
680 +  Result := FBlobData[index];
681 + end;
682 +
683 + function TSQLXMLReader.GetBlobDataCount: integer;
684 + begin
685 +  Result := Length(FBlobData);
686 + end;
687 +
688 + function TSQLXMLReader.GetTagName(xmltag: TXMLTag): string;
689 + var i: TXMLTag;
690 + begin
691 +  Result := 'unknown';
692 +  for i := xtBlob to xtElt do
693 +    if XMLTagDefs[i].XMLTag = xmltag then
694 +    begin
695 +      Result := XMLTagDefs[i].TagValue;
696 +      Exit;
697 +    end;
698 + end;
699 +
700 + procedure TSQLXMLReader.ProcessAttributeValue(attrValue: string);
701 + begin
702 +  case FXMLTagStack[FXMLTagIndex] of
703 +  xtBlob:
704 +    if FAttributeName = 'subtype' then
705 +      FBlobData[FCurrentBlob].SubType := StrToInt(attrValue)
706 +    else
707 +      ShowError(sXMLAttributeError,[FAttributeName,attrValue]);
708 +
709 +  xtArray:
710 +    if FAttributeName = 'sqltype' then
711 +      FArrayData[FCurrentArray].SQLType := StrToInt(attrValue)
712 +    else
713 +    if FAttributeName = 'relation_name' then
714 +      FArrayData[FCurrentArray].relationName := attrValue
715 +    else
716 +    if FAttributeName = 'column_name' then
717 +      FArrayData[FCurrentArray].columnName := attrValue
718 +    else
719 +    if FAttributeName = 'dim' then
720 +      FArrayData[FCurrentArray].Dim := StrToInt(attrValue)
721 +    else
722 +    if FAttributeName = 'length' then
723 +      FArrayData[FCurrentArray].Size := StrToInt(attrValue)
724 +    else
725 +    if FAttributeName = 'scale' then
726 +      FArrayData[FCurrentArray].Scale := StrToInt(attrValue)
727 +    else
728 +    if FAttributeName = 'charset' then
729 +      FArrayData[FCurrentArray].CharSet := attrValue
730 +    else
731 +    if FAttributeName = 'bounds' then
732 +      ProcessBoundsList(attrValue)
733 +    else
734 +      ShowError(sXMLAttributeError,[FAttributeName,attrValue]);
735 +
736 +  xtElt:
737 +    if FAttributeName = 'ix' then
738 +      with FArrayData[FCurrentArray] do
739 +        Index[CurrentRow] :=  StrToInt(attrValue)
740 +     else
741 +        ShowError(sXMLAttributeError,[FAttributeName,attrValue]);
742 +  end;
743 + end;
744 +
745 + procedure TSQLXMLReader.ProcessBoundsList(boundsList: string);
746 + var list: TStringList;
747 +    i,j: integer;
748 + begin
749 +  list := TStringList.Create;
750 +  try
751 +    list.Delimiter := ',';
752 +    list.DelimitedText := boundsList;
753 +    with FArrayData[FCurrentArray] do
754 +    begin
755 +      if dim <> list.Count then
756 +        ShowError(sInvalidBoundsList,[boundsList]);
757 +      SetLength(bounds,dim);
758 +      for i := 0 to list.Count - 1 do
759 +      begin
760 +        j := Pos(':',list[i]);
761 +        if j = 0 then
762 +          raise Exception.CreateFmt(sInvalidBoundsList,[boundsList]);
763 +        bounds[i].LowerBound := StrToInt(system.copy(list[i],1,j-1));
764 +        bounds[i].UpperBound := StrToInt(system.copy(list[i],j+1,length(list[i])-j));
765 +      end;
766 +    end;
767 +  finally
768 +    list.Free;
769 +  end;
770 + end;
771 +
772 + procedure TSQLXMLReader.ProcessTagValue(tagValue: string);
773 +
774 +  function nibble(hex: char): byte;
775 +  begin
776 +    case hex of
777 +    '0': Result := 0;
778 +    '1': Result := 1;
779 +    '2': Result := 2;
780 +    '3': Result := 3;
781 +    '4': Result := 4;
782 +    '5': Result := 5;
783 +    '6': Result := 6;
784 +    '7': Result := 7;
785 +    '8': Result := 8;
786 +    '9': Result := 9;
787 +    'a','A': Result := 10;
788 +    'b','B': Result := 11;
789 +    'c','C': Result := 12;
790 +    'd','D': Result := 13;
791 +    'e','E': Result := 14;
792 +    'f','F': Result := 15;
793 +    end;
794 +  end;
795 +
796 +  procedure RemoveWhiteSpace(var hexData: string);
797 +  var i: integer;
798 +  begin
799 +    {Remove White Space}
800 +    i := 1;
801 +    while i <= length(hexData) do
802 +    begin
803 +      case hexData[i] of
804 +      ' ',#9,#10,#13:
805 +        begin
806 +          if i < Length(hexData) then
807 +            Move(hexData[i+1],hexData[i],Length(hexData)-i);
808 +          SetLength(hexData,Length(hexData)-1);
809 +        end;
810 +      else
811 +        Inc(i);
812 +      end;
813 +    end;
814 +  end;
815 +
816 +  procedure WriteToBlob(hexData: string);
817 +  var i,j : integer;
818 +      blength: integer;
819 +      P: PChar;
820 +  begin
821 +    RemoveWhiteSpace(hexData);
822 +    if odd(length(hexData)) then
823 +      ShowError(sBinaryBlockMustbeEven,[nil]);
824 +    blength := Length(hexData) div 2;
825 +    IBAlloc(FBlobBuffer,0,blength);
826 +    j := 1;
827 +    P := FBlobBuffer;
828 +    for i := 1 to blength do
829 +    begin
830 +      P^ := char((nibble(hexData[j]) shl 4) or nibble(hexdata[j+1]));
831 +      Inc(j,2);
832 +      Inc(P);
833 +    end;
834 +    FBlobData[FCurrentBlob].BlobIntf.Write(FBlobBuffer^,blength);
835 +  end;
836 +
837 + begin
838 +  if tagValue = '' then Exit;
839 +  case FXMLTagStack[FXMLTagIndex] of
840 +  xtBlob:
841 +    WriteToBlob(tagValue);
842 +
843 +  xtElt:
844 +    with FArrayData[FCurrentArray] do
845 +      ArrayIntf.SetAsString(index,tagValue);
846 +
847 +  end;
848 + end;
849 +
850 + procedure TSQLXMLReader.XMLTagInit(xmltag: TXMLTag);
851 + begin
852 +  if FXMLTagIndex > MaxXMLTags then
853 +    ShowError(sXMLStackOverFlow,[nil]);
854 +  Inc(FXMLTagIndex);
855 +  FXMLTagStack[FXMLTagIndex] := xmltag;
856 +  FXMLString := '';
857 +
858 +  case xmltag of
859 +  xtBlob:
860 +    begin
861 +      Inc(FCurrentBlob);
862 +      SetLength(FBlobData,FCurrentBlob+1);
863 +      FBlobData[FCurrentBlob].BlobIntf := nil;
864 +      FBlobData[FCurrentBlob].SubType := 0;
865 +    end;
866 +
867 +  xtArray:
868 +    begin
869 +      Inc(FCurrentArray);
870 +      SetLength(FArrayData,FCurrentArray+1);
871 +      with FArrayData[FCurrentArray] do
872 +      begin
873 +        ArrayIntf := nil;
874 +        SQLType := 0;
875 +        dim := 0;
876 +        Size := 0;
877 +        Scale := 0;
878 +        CharSet := 'NONE';
879 +        SetLength(Index,0);
880 +        CurrentRow := -1;
881 +      end;
882 +    end;
883 +
884 +  xtElt:
885 +      with FArrayData[FCurrentArray] do
886 +        Inc(CurrentRow)
887 +  end;
888 + end;
889 +
890 + function TSQLXMLReader.XMLTagEnd(var xmltag: TXMLTag): boolean;
891 + begin
892 +  if FXMLTagIndex = 0 then
893 +    ShowError(sXMLStackUnderflow,[nil]);
894 +
895 +  xmlTag := FXMLTagStack[FXMLTagIndex];
896 +  case FXMLTagStack[FXMLTagIndex] of
897 +  xtBlob:
898 +    FBlobData[FCurrentBlob].BlobIntf.Close;
899 +
900 +  xtArray:
901 +    FArrayData[FCurrentArray].ArrayIntf.SaveChanges;
902 +
903 +  xtElt:
904 +    Dec(FArrayData[FCurrentArray].CurrentRow);
905 +  end;
906 +  Dec(FXMLTagIndex);
907 +  Result := FXMLTagIndex = 0;
908 + end;
909 +
910 + procedure TSQLXMLReader.XMLTagEnter;
911 + var aCharSetID: integer;
912 + begin
913 +  if Database = nil then
914 +    ShowError(sNoDatabase);
915 +  if Transaction = nil then
916 +    ShowError(sNoTransaction);
917 +  case FXMLTagStack[FXMLTagIndex] of
918 +  xtBlob:
919 +    begin
920 +      Database.Connected := true;
921 +      Transaction.Active := true;
922 +      FBlobData[FCurrentBlob].BlobIntf := Database.Attachment.CreateBlob(
923 +        Transaction.TransactionIntf,FBlobData[FCurrentBlob].SubType);
924 +    end;
925 +
926 +  xtArray:
927 +    with FArrayData[FCurrentArray] do
928 +    begin
929 +      Database.Connected := true;
930 +      Transaction.Active := true;
931 +      Database.Attachment.CharSetName2CharSetID(CharSet,aCharSetID);
932 +      SetLength(Index,dim);
933 +      ArrayIntf := Database.Attachment.CreateArray(
934 +                     Transaction.TransactionIntf,
935 +                     Database.Attachment.CreateArrayMetaData(SQLType,
936 +                       relationName,columnName,Scale,Size,
937 +                       aCharSetID,dim,bounds)
938 +                     );
939 +    end;
940 +  end;
941 + end;
942 +
943 + {This is where the XML tags are identified and the token stream modified in
944 + consequence}
945 +
946 + function TSQLXMLReader.TokenFound(var token: TSQLTokens): boolean;
947 +
948 + procedure NotAnXMLTag;
949 + begin
950 +   begin
951 +     if FXMLTagIndex = 0 then
952 +     {nothing to do with XML so go back to processing SQL}
953 +     begin
954 +       QueueToken(token);
955 +       ReleaseQueue(token);
956 +       FXMLState := stNoXML
957 +     end
958 +     else
959 +     begin
960 +       {Not an XML tag, so just push back to XML Data}
961 +       FXMLState := stXMLData;
962 +       FXMLString += GetQueuedText;
963 +       ResetQueue;
964 +     end;
965 +   end;
966 + end;
967 +
968 + var XMLTag: TXMLTag;
969 + begin
970 +  Result := inherited TokenFound(token);
971 +  if not Result then Exit;
972 +
973 +  case FXMLState of
974 +  stNoXML:
975 +    if token = sqltLT then
976 +    begin
977 +      ResetQueue;
978 +      QueueToken(token); {save in case this is not XML}
979 +      FXMLState := stInTag;
980 +    end;
981 +
982 +  stInTag:
983 +    {Opening '<' found, now looking for tag name or end tag marker}
984 +    case token of
985 +    sqltIdentifier:
986 +      begin
987 +        if FindTag(TokenText,XMLTag) then
988 +        begin
989 +          XMLTagInit(XMLTag);
990 +          QueueToken(token);
991 +          FXMLState := stInTagBody;
992 +        end
993 +        else
994 +          NotAnXMLTag;
995 +      end;
996 +
997 +    sqltForwardSlash:
998 +      FXMLState := stInEndTag;
999 +
1000 +    else
1001 +      NotAnXMLTag;
1002 +    end {case token};
1003 +
1004 +  stInTagBody:
1005 +    {Tag name found. Now looking for attribute or closing '>'}
1006 +    case token of
1007 +    sqltIdentifier:
1008 +      begin
1009 +        FAttributeName := TokenText;
1010 +        QueueToken(token);
1011 +        FXMLState := stAttribute;
1012 +      end;
1013 +
1014 +    sqltGT:
1015 +      begin
1016 +        ResetQueue;
1017 +        XMLTagEnter;
1018 +        FXMLState := stXMLData;
1019 +      end;
1020 +
1021 +    sqltSpace,
1022 +    sqltEOL:
1023 +      QueueToken(token);
1024 +
1025 +    else
1026 +      NotAnXMLTag;
1027 +    end {case token};
1028 +
1029 +  stAttribute:
1030 +    {Attribute name found. Must be followed by an '=', a '>' or another tag name}
1031 +    case token of
1032 +      sqltEquals:
1033 +      begin
1034 +        QueueToken(token);
1035 +        FXMLState := stAttributeValue;
1036 +      end;
1037 +
1038 +      sqltSpace,
1039 +      sqltEOL:
1040 +        QueueToken(token);
1041 +
1042 +      sqltIdentifier:
1043 +        begin
1044 +          ProcessAttributeValue('');
1045 +          FAttributeName := TokenText;
1046 +          QueueToken(token);
1047 +          FXMLState := stAttribute;
1048 +        end;
1049 +
1050 +      sqltGT:
1051 +        begin
1052 +          ProcessAttributeValue('');
1053 +          ResetQueue;
1054 +          XMLTagEnter;
1055 +          FXMLState := stXMLData;
1056 +        end;
1057 +
1058 +      else
1059 +        NotAnXMLTag;
1060 +    end; {case token}
1061 +
1062 +  stAttributeValue:
1063 +    {Looking for attribute value as a single identifier or a double quoted value}
1064 +    case token of
1065 +    sqltIdentifier,sqltIdentifierInDoubleQuotes:
1066 +      begin
1067 +        ProcessAttributeValue(TokenText);
1068 +        QueueToken(token);
1069 +        FXMLState := stInTagBody;
1070 +      end;
1071 +
1072 +    sqltSpace,
1073 +    sqltEOL:
1074 +      QueueToken(token);
1075 +
1076 +    else
1077 +      NotAnXMLTag;
1078 +    end; {case token}
1079 +
1080 +  stXMLData:
1081 +    if token = sqltLT then
1082 +    begin
1083 +      QueueToken(token); {save in case this is not XML}
1084 +      FXMLState := stInTag;
1085 +    end
1086 +    else
1087 +      FXMLString += TokenText;
1088 +
1089 +  stInEndTag:
1090 +    {Opening '</' found, now looking for tag name}
1091 +    case token of
1092 +    sqltIdentifier:
1093 +      begin
1094 +        if FindTag(TokenText,XMLTag) and (XMLTag = FXMLTagStack[FXMLTagIndex]) then
1095 +        begin
1096 +          QueueToken(token);
1097 +          FXMLState := stInEndTagBody;
1098 +        end
1099 +        else
1100 +          ShowError(sInvalidEndTag,[TokenText]);
1101 +      end;
1102 +    else
1103 +      NotAnXMLTag;
1104 +    end {case token};
1105 +
1106 +  stInEndTagBody:
1107 +  {End tag name found, now looping for closing '>'}
1108 +    case Token of
1109 +    sqltGT:
1110 +      begin
1111 +        ProcessTagValue(FXMLString);
1112 +        if XMLTagEnd(XMLTag) then
1113 +        begin
1114 +          ResetQueue;
1115 +          QueueToken(sqltColon,':');
1116 +          case XMLTag of
1117 +            xtBlob:
1118 +              QueueToken(sqltIdentifier,Format(ibx_blob+'%d',[FCurrentBlob]));
1119 +
1120 +            xtArray:
1121 +              QueueToken(sqltIdentifier, Format(ibx_array+'%d',[FCurrentArray]));
1122 +          end;
1123 +          ReleaseQueue(token);
1124 +          FXMLState := stNoXML;
1125 +       end
1126 +       else
1127 +         FXMLState := stXMLData;
1128 +      end;
1129 +
1130 +    sqltSpace,
1131 +    sqltEOL:
1132 +      QueueToken(token);
1133 +
1134 +    else
1135 +      ShowError(sBadEndTagClosing);
1136 +    end; {case token}
1137 +
1138 +  end {Case FState};
1139 +
1140 +  {Only allow token to be returned if not processing an XML tag}
1141 +
1142 +  Result := FXMLState = stNoXML;
1143 + end;
1144 +
1145 + procedure TSQLXMLReader.ShowError(msg: string; params: array of const);
1146 + begin
1147 +  raise EIBClientError.CreateFmt(GetErrorPrefix + msg,params);
1148 + end;
1149 +
1150 + procedure TSQLXMLReader.ShowError(msg: string);
1151 + begin
1152 +  ShowError(msg,[nil]);
1153 + end;
1154 +
1155 + constructor TSQLXMLReader.Create;
1156 + begin
1157 +  inherited;
1158 +  FXMLState := stNoXML;
1159 + end;
1160 +
1161 + procedure TSQLXMLReader.FreeDataObjects;
1162 + begin
1163 +  FXMLTagIndex := 0;
1164 +  SetLength(FBlobData,0);
1165 +  FCurrentBlob := -1;
1166 +  SetLength(FArrayData,0);
1167 +  FCurrentArray := -1;
1168 + end;
1169 +
1170 + class function TSQLXMLReader.FormatBlob(Field: ISQLData): string;
1171 + var TextOut: TStrings;
1172 + begin
1173 +  TextOut := TStringList.Create;
1174 +  try
1175 +    TextOut.Add(Format('<blob subtype="%d">',[Field.getSubtype]));
1176 +    StringToHex(Field.AsString,TextOut,BlobLineLength);
1177 +    TextOut.Add('</blob>');
1178 +    Result := TextOut.Text;
1179 +  finally
1180 +    TextOut.Free;
1181 +  end;
1182 + end;
1183 +
1184 + class function TSQLXMLReader.FormatArray(Database: TIBDatabase; ar: IArray
1185 +  ): string;
1186 + var index: array of integer;
1187 +    TextOut: TStrings;
1188 +
1189 +    procedure AddElements(dim: integer; indent:string = ' ');
1190 +    var i: integer;
1191 +        recurse: boolean;
1192 +    begin
1193 +      SetLength(index,dim+1);
1194 +      recurse := dim < ar.GetDimensions - 1;
1195 +      with ar.GetBounds[dim] do
1196 +      for i := LowerBound to UpperBound do
1197 +      begin
1198 +        index[dim] := i;
1199 +        if recurse then
1200 +        begin
1201 +          TextOut.Add(Format('%s<elt id="%d">',[indent,i]));
1202 +          AddElements(dim+1,indent + ' ');
1203 +          TextOut.Add('</elt>');
1204 +        end
1205 +        else
1206 +        if ((ar.GetSQLType = SQL_TEXT) or (ar.GetSQLType = SQL_VARYING)) and
1207 +           (ar.GetCharSetID = 1) then
1208 +           TextOut.Add(Format('%s<elt ix="%d">%s</elt>',[indent,i,StringToHex(ar.GetAsString(index))]))
1209 +        else
1210 +          TextOut.Add(Format('%s<elt ix="%d">%s</elt>',[indent,i,ar.GetAsString(index)]));
1211 +      end;
1212 +    end;
1213 +
1214 + var
1215 +    s: string;
1216 +    bounds: TArrayBounds;
1217 +    i: integer;
1218 +    boundsList: string;
1219 + begin
1220 +  TextOut := TStringList.Create;
1221 +  try
1222 +    if ar.GetCharSetWidth = 0 then
1223 +      s := Format('<array dim = "%d" sqltype = "%d" length = "%d" relation_name = "%s" column_name = "%s"',
1224 +                              [ar.GetDimensions,ar.GetSQLType,ar.GetSize,
1225 +                               ar.GetTableName,ar.GetColumnName])
1226 +    else
1227 +      s := Format('<array dim = "%d" sqltype = "%d" length = "%d" relation_name = "%s" column_name = "%s"',
1228 +                                [ar.GetDimensions,ar.GetSQLType,ar.GetSize div ar.GetCharSetWidth,
1229 +                                 ar.GetTableName,ar.GetColumnName]);
1230 +    case ar.GetSQLType of
1231 +    SQL_DOUBLE, SQL_FLOAT, SQL_LONG, SQL_SHORT, SQL_D_FLOAT, SQL_INT64:
1232 +       s += Format(' scale = "%d"',[ ar.GetScale]);
1233 +    SQL_TEXT,
1234 +    SQL_VARYING:
1235 +      s += Format(' charset = "%s"',[Database.Attachment.GetCharsetName(ar.GetCharSetID)]);
1236 +    end;
1237 +    bounds := ar.GetBounds;
1238 +    boundsList := '';
1239 +    for i := 0 to length(bounds) - 1 do
1240 +    begin
1241 +      if i <> 0 then boundsList += ',';
1242 +      boundsList += Format('%d:%d',[bounds[i].LowerBound,bounds[i].UpperBound]);
1243 +    end;
1244 +    s += Format(' bounds="%s"',[boundsList]);
1245 +    s += '>';
1246 +    TextOut.Add(s);
1247 +
1248 +    SetLength(index,0);
1249 +    AddElements(0);
1250 +    TextOut.Add('</array>');
1251 +    Result := TextOut.Text;
1252 +  finally
1253 +    TextOut.Free;
1254 +  end;       end;
1255 +
1256 + procedure TSQLXMLReader.Reset;
1257 + begin
1258 +  inherited Reset;
1259 +  FreeDataObjects;
1260 +  FXMLString := '';
1261 +  FreeMem(FBlobBuffer);
1262 + end;
1263 +
1264  
1265  
1266   { TIBXScript }
# Line 498 | Line 1268 | end;
1268   constructor TIBXScript.Create(aOwner: TComponent);
1269   begin
1270    inherited Create(aOwner);
1271 <  FSymbolStream := TBatchSymbolStream.Create;
502 <  FSymbolStream.OnNextLine := @EchoNextLine;
1271 >  SetSQLStatementReader(TBatchSQLStatementReader.Create);
1272   end;
1273  
1274   function TIBXScript.PerformUpdate(SQLFile: string; aAutoDDL: boolean): boolean;
# Line 517 | Line 1286 | end;
1286  
1287   function TIBXScript.RunScript(SQLFile: string): boolean;
1288   begin
1289 <  TBatchSymbolStream(FSymbolStream).SetStreamSource(SQLFile);
1289 >  TBatchSQLStatementReader(FSQLReader).SetStreamSource(SQLFile);
1290    Result := ProcessStream;
1291   end;
1292  
1293   function TIBXScript.RunScript(SQLStream: TStream): boolean;
1294   begin
1295 <  TBatchSymbolStream(FSymbolStream).SetStreamSource(SQLStream);
1295 >  TBatchSQLStatementReader(FSQLReader).SetStreamSource(SQLStream);
1296    Result := ProcessStream;
1297   end;
1298  
1299   function TIBXScript.RunScript(SQLLines: TStrings): boolean;
1300   begin
1301 <  TBatchSymbolStream(FSymbolStream).SetStreamSource(SQLLines);
1301 >  TBatchSQLStatementReader(FSQLReader).SetStreamSource(SQLLines);
1302    Result := ProcessStream;
1303   end;
1304  
1305   function TIBXScript.ExecSQLScript(sql: string): boolean;
537 var s: TStringList;
1306   begin
1307 <  s := TStringList.Create;
1308 <  try
541 <    s.Text := sql;
542 <    TBatchSymbolStream(FSymbolStream).SetStreamSource(s);
543 <    Result := ProcessStream;
544 <  finally
545 <    s.Free;
546 <  end;
1307 >  TBatchSQLStatementReader(FSQLReader).SetStringStreamSource(sql);
1308 >  Result := ProcessStream;
1309   end;
1310  
1311   { TCustomIBXScript }
# Line 579 | Line 1341 | begin
1341     FISQL.SQL.Text := stmt;
1342     FISQL.Transaction := GetTransaction;
1343     FISQL.Transaction.Active := true;
1344 <   FISQL.ParamCheck := not FIBSQLProcessor.HasBegin; {Probably PSQL}
1344 > //   FISQL.ParamCheck := not FSQLReader.HasBegin; {Probably PSQL}
1345     FISQL.Prepare;
1346     FISQL.Statement.EnableStatistics(ShowPerformanceStats);
1347  
# Line 618 | Line 1380 | end;
1380  
1381   function TCustomIBXScript.GetOnProgressEvent: TOnProgressEvent;
1382   begin
1383 <  Result := FSymbolStream.OnProgressEvent;
1383 >  Result := FSQLReader.OnProgressEvent;
1384   end;
1385  
1386   function TCustomIBXScript.GetTransaction: TIBTransaction;
# Line 651 | Line 1413 | begin
1413   if not (csLoading in ComponentState) and (FDatabase = AValue) then Exit;
1414   FDatabase := AValue;
1415   FISQL.Database := AValue;
1416 < FIBXMLProcessor.Database := AValue;
1416 > FSQLReader.Database := AValue;
1417   FInternalTransaction.Active := false;
1418   FInternalTransaction.DefaultDatabase := AValue;
1419   end;
# Line 668 | Line 1430 | end;
1430  
1431   procedure TCustomIBXScript.SetOnProgressEvent(AValue: TOnProgressEvent);
1432   begin
1433 <  FSymbolStream.OnProgressEvent := AValue;
1433 >  FSQLReader.OnProgressEvent := AValue;
1434   end;
1435  
1436   procedure TCustomIBXScript.SetParamValue(SQLVar: ISQLParam);
1437   var BlobID: TISC_QUAD;
1438      ix: integer;
1439   begin
1440 <  if (SQLVar.SQLType = SQL_BLOB) and (Pos(ibx_blob,SQLVar.Name) = 1) then
1440 >  if (SQLVar.SQLType = SQL_BLOB) and (Pos(TSQLXMLReader.ibx_blob,SQLVar.Name) = 1) then
1441    begin
1442 <    ix := StrToInt(system.copy(SQLVar.Name,length(ibx_blob)+1,length(SQLVar.Name)-length(ibx_blob)));
1443 <    SQLVar.AsBlob := FIBXMLProcessor.BlobData[ix].BlobIntf;
1442 >    ix := StrToInt(system.copy(SQLVar.Name,length(TSQLXMLReader.ibx_blob)+1,length(SQLVar.Name)-length(TSQLXMLReader.ibx_blob)));
1443 >    SQLVar.AsBlob := FSQLReader.BlobData[ix].BlobIntf;
1444      Exit;
1445    end
1446    else
1447 <  if (SQLVar.SQLType = SQL_ARRAY) and (Pos(ibx_array,SQLVar.Name) = 1) then
1447 >  if (SQLVar.SQLType = SQL_ARRAY) and (Pos(TSQLXMLReader.ibx_array,SQLVar.Name) = 1) then
1448    begin
1449 <    ix := StrToInt(system.copy(SQLVar.Name,length(ibx_array)+1,length(SQLVar.Name)-length(ibx_array)));
1450 <    SQLVar.AsArray := FIBXMLProcessor.ArrayData[ix].ArrayIntf;
1449 >    ix := StrToInt(system.copy(SQLVar.Name,length(TSQLXMLReader.ibx_array)+1,length(SQLVar.Name)-length(TSQLXMLReader.ibx_array)));
1450 >    SQLVar.AsArray := FSQLReader.ArrayData[ix].ArrayIntf;
1451      Exit;
1452    end;
1453  
# Line 714 | Line 1476 | function TCustomIBXScript.ProcessStream:
1476   var stmt: string;
1477   begin
1478    Result := false;
1479 <  while FIBSQLProcessor.GetNextStatement(FSymbolStream,stmt) do
1479 >  while FSQLReader.GetNextStatement(stmt) do
1480    try
1481 < //    writeln('stmt = ',stmt);
1482 <    if trim(stmt) = '' then continue;
1481 >    stmt := trim(stmt);
1482 > //    writeln('stmt = "',stmt,'"');
1483 >    if stmt = '' then continue;
1484      if not ProcessStatement(stmt) then
1485        ExecSQL(stmt);
1486  
# Line 725 | Line 1488 | begin
1488        begin
1489          with GetTransaction do
1490            if InTransaction then Rollback;
1491 <        FSymbolStream.Terminator := DefaultTerminator;
1491 >        FSQLReader.Terminator := TSQLStatementReader.DefaultTerminator;
1492          if assigned(OnErrorLog) then
1493          begin
1494 <          Add2Log(Format(sStatementError,[FSymbolStream.GetErrorPrefix,
1494 >          Add2Log(Format(sStatementError,[FSQLReader.GetErrorPrefix,
1495                               E.Message,stmt]),true);
1496                               if StopOnFirstError then Exit;
1497          end
# Line 739 | Line 1502 | begin
1502    Result := true;
1503   end;
1504  
1505 + procedure TCustomIBXScript.SetSQLStatementReader(
1506 +  SQLStatementReader: TSQLStatementReader);
1507 + begin
1508 +  FSQLReader := SQLStatementReader;
1509 +  FSQLReader.OnNextLine := @EchoNextLine;
1510 +  FSQLReader.Transaction := FInternalTransaction;
1511 + end;
1512 +
1513   function TCustomIBXScript.ProcessStatement(stmt: string): boolean;
1514   var command: string;
1515  
# Line 850 | Line 1621 | var  RegexObj: TRegExpr;
1621       LoginPrompt: boolean;
1622   begin
1623    Result := false;
1624 <  Terminator := FSymbolStream.Terminator;
1624 >  Terminator := FSQLReader.Terminator;
1625    RegexObj := TRegExpr.Create;
1626    try
1627      {process create database}
# Line 868 | Line 1639 | begin
1639          OnCreateDatabase(self,FileName);
1640        stmt := 'CREATE DATABASE ''' + FileName + '''' + system.copy(stmt,RegexObj.MatchPos[3], RegexObj.MatchLen[3]);
1641        UpdateUserPassword;
1642 <      FDatabase.Connected := false;
1642 >      if FDatabase.Connected then
1643 >        FDatabase.Dropdatabase;
1644        FDatabase.CreateDatabase(stmt);
873      FDatabase.Connected := false;
874      ExtractUserInfo;
875      FDatabase.Connected := true;
1645        Result := true;
1646        Exit;
1647      end;
# Line 920 | Line 1689 | begin
1689      RegexObj.Expression := '^ *SET +TERM +(.) *(\' + Terminator + '|)';
1690      if RegexObj.Exec(stmt) then
1691      begin
1692 <       FSymbolStream.Terminator := RegexObj.Match[1][1];
1692 >       FSQLReader.Terminator := RegexObj.Match[1][1];
1693         Result := true;
1694         Exit;
1695      end;
# Line 946 | Line 1715 | begin
1715      begin
1716        command := AnsiUpperCase(RegexObj.Match[1]);
1717        param := trim(RegexObj.Match[2]);
1718 +      if command = 'GENERATOR' then
1719 +      begin
1720 +        Result := false;
1721 +        Exit;
1722 +      end;
1723        if command = 'AUTODDL' then
1724          AutoDDL := ((RegexObj.MatchLen[2] = 0) and not AutoDDL) or
1725                     (RegexObj.MatchLen[2] > 0) and Toggle(param)
# Line 985 | Line 1759 | begin
1759        begin
1760          if assigned(DataOutputFormatter) then
1761            DataOutputFormatter.SetCommand(command,param,stmt,Result);
1762 <        if not Result and assigned(OnSetStatement) then
1763 <          OnSetStatement(self,command,param,stmt,Result)
1764 <        else
1765 <          raise Exception.CreateFmt(sInvalidSetStatement, [command,stmt]);
1762 >        if not Result then
1763 >        begin
1764 >          if assigned(OnSetStatement) then
1765 >            OnSetStatement(self,command,param,stmt,Result)
1766 >          else
1767 >            raise Exception.CreateFmt(sInvalidSetStatement, [command,stmt]);
1768 >        end;
1769          Exit;
1770        end;
1771        Result := true;
# Line 1004 | Line 1781 | procedure TCustomIBXScript.SetTransactio
1781   begin
1782    if FTransaction = AValue then Exit;
1783    FTransaction := AValue;
1784 <  FIBXMLProcessor.Transaction := AValue;
1784 >  if FTransaction = nil then
1785 >    FSQLReader.Transaction := FInternalTransaction
1786 >  else
1787 >    FSQLReader.Transaction := FTransaction;
1788   end;
1789  
1790   constructor TCustomIBXScript.Create(aOwner: TComponent);
# Line 1015 | Line 1795 | begin
1795    FAutoDDL := true;
1796    FISQL := TIBSQL.Create(self);
1797    FISQL.ParamCheck := true;
1018  FIBXMLProcessor := TIBXMLProcessor.Create;
1019  FIBSQLProcessor := TIBSQLProcessor.Create(FIBXMLProcessor);
1798    FInternalTransaction := TIBTransaction.Create(self);
1799    FInternalTransaction.Params.Clear;
1800    FInternalTransaction.Params.Add('concurrency');
# Line 1025 | Line 1803 | end;
1803  
1804   destructor TCustomIBXScript.Destroy;
1805   begin
1806 <  if FIBSQLProcessor <> nil then FIBSQLProcessor.Free;
1029 <  if FIBXMLProcessor <> nil then FIBXMLProcessor.Free;
1030 <  if FSymbolStream <> nil then FSymbolStream.Free;
1806 >  if FSQLReader <> nil then FSQLReader.Free;
1807    if FISQL <> nil then FISQL.Free;
1808    if FInternalTransaction <> nil then FInternalTransaction.Free;
1809    inherited Destroy;
# Line 1038 | Line 1814 | begin
1814    if assigned(DataOutputFormatter) then
1815      DataOutputFormatter.DataOut(aSQLText,@Add2Log)
1816    else
1817 <    FSymbolStream.ShowError(sNoSelectSQL,[nil]);
1817 >    FSQLReader.ShowError(sNoSelectSQL);
1818   end;
1819  
1820 < { TIBSQLProcessor }
1045 <
1046 < procedure TIBSQLProcessor.AddToSQL(const Symbol: string);
1047 < begin
1048 <  FSQLText := FSQLText +  Symbol;
1049 < //  writeln('SQL = ',FSQLText);
1050 < end;
1820 > { TInteractiveSQLStatementReader }
1821  
1822 < procedure TIBSQLProcessor.SetState(AState: TSQLStates);
1822 > function TInteractiveSQLStatementReader.GetErrorPrefix: string;
1823   begin
1824 <  if FStackIndex > 16 then
1055 <    FSymbolStream.ShowError(sStackOverFlow,[nil]);
1056 <  FStack[FStackIndex] := FState;
1057 <  Inc(FStackIndex);
1058 <  FState := AState
1059 < end;
1060 <
1061 < function TIBSQLProcessor.PopState: TSQLStates;
1062 < begin
1063 <  if FStackIndex = 0 then
1064 <    FSymbolStream.ShowError(sStackUnderflow,[nil]);
1065 <  Dec(FStackIndex);
1066 <  Result := FStack[FStackIndex]
1067 < end;
1068 <
1069 < constructor TIBSQLProcessor.Create(XMLProcessor: TIBXMLProcessor);
1070 < begin
1071 <  inherited Create;
1072 <  FXMLProcessor := XMLProcessor;
1824 >  Result := '';
1825   end;
1826  
1827 < function TIBSQLProcessor.GetNextStatement(SymbolStream: TSymbolStream;
1076 <  var stmt: string): boolean;
1077 < var Symbol: TSQLSymbol;
1078 <    NonSpace: boolean;
1079 <    Done: boolean;
1827 > function TInteractiveSQLStatementReader.GetNextLine(var Line: string): boolean;
1828   begin
1829 <  FSQLText := '';
1830 <  FState := stInit;
1831 <  FHasBegin := false;
1832 <  FSymbolStream := SymbolStream;
1833 <  FXMLProcessor.NextStatement;
1834 <  SymbolStream.NextStatement;
1087 <
1088 <  Result := true;
1089 <  Done := false;
1090 <  NonSpace := false;
1091 <  while not Done do
1092 <  with SymbolStream do
1829 >  if FNextStatement then
1830 >    write(FPrompt)
1831 >  else
1832 >    write(FContinuePrompt);
1833 >  Result := not system.EOF;
1834 >  if Result then
1835    begin
1836 <    if FState = stError then
1837 <      ShowError(sErrorState,[nil]);
1096 <    Symbol := GetSymbol;
1097 < //    writeln('Symbol = ',Symbol,' Value = ',SymbolValue);
1098 <    if not (Symbol in [' ',sqEOL]) then
1099 <      NonSpace := true;
1100 <
1101 <    case Symbol of
1102 <    sqTag:
1103 <      begin
1104 <        if FState in [stInSQL,stNested] then
1105 <          AddToSQL(FXMLProcessor.AnalyseXML(SymbolStream));
1106 <      end;
1107 <
1108 <    sqTerminator:
1109 <        case FState of
1110 <        stInit: {ignore empty statement};
1111 <
1112 <        stInSQL:
1113 <            Done := true;
1114 <
1115 <       stNested:
1116 <         AddToSQL(Terminator);
1117 <
1118 <       stInDeclaration:
1119 <         begin
1120 <           FState := PopState;
1121 <           AddToSQL(Terminator);
1122 <         end;
1123 <
1124 <       else
1125 <         ShowError(sTerminatorUnknownState,[FState]);
1126 <       end;
1127 <
1128 <    ';':
1129 <        begin
1130 <          if FState = stInDeclaration then
1131 <            FState := PopState;
1132 <          AddToSQL(';');
1133 <        end;
1134 <
1135 <    '*':
1136 <      begin
1137 <       AddToSQL('*');
1138 <       if FState =  stInit then
1139 <          FState := stInSQL
1140 <      end;
1141 <
1142 <    '/':
1143 <      begin
1144 <       AddToSQL('/');
1145 <       if FState =  stInit then
1146 <          FState := stInSQL
1147 <      end;
1148 <
1149 <    sqComment,
1150 <    sqQuotedString,
1151 <    sqDoubleQuotedString:
1152 <      if FState <> stInit then
1153 <        AddToSQL(SymbolValue);
1154 <
1155 <    sqCommentLine:
1156 <      if FState <> stInit then
1157 <      AddToSQL(SymbolValue + LineEnding);
1158 <
1159 <    sqEnd:
1160 <      begin
1161 <        AddToSQL(SymbolValue);
1162 <        case FState of
1163 <        stNested:
1164 <          begin
1165 <            if FNested = 0 then
1166 <            begin
1167 <              FState := PopState;
1168 <              if not FInCase then
1169 <              begin
1170 <                FState := stInit;
1171 <                Done := true;
1172 <              end
1173 <              else
1174 <                FInCase := false;
1175 <            end
1176 <           else
1177 <              Dec(FNested)
1178 <          end;
1179 <          {Otherwise ignore}
1180 <        end
1181 <      end;
1182 <
1183 <    sqBegin:
1184 <      begin
1185 <        FHasBegin := true;
1186 <        AddToSQL(SymbolValue);
1187 <        case FState of
1188 <        stNested:
1189 <          Inc(FNested);
1190 <
1191 <        stInSQL,
1192 <        stInit:
1193 <          SetState(stNested);
1194 <        end
1195 <      end;
1196 <
1197 <    sqCase:
1198 <    begin
1199 <      AddToSQL(SymbolValue);
1200 <      case FState of
1201 <      stNested:
1202 <        Inc(FNested);
1203 <
1204 <      stInSQL,
1205 <      stInit:
1206 <        begin
1207 <          FInCase := true;
1208 <          SetState(stNested);
1209 <        end;
1210 <      end
1211 <    end;
1212 <
1213 <    sqDeclare:
1214 <      begin
1215 <        AddToSQL(SymbolValue);
1216 <        if FState in [stInit,stInSQL] then
1217 <          SetState(stInDeclaration)
1218 <      end;
1219 <
1220 <    sqString:
1221 <      begin
1222 <        AddToSQL(SymbolValue);
1223 <        if FState = stInit then
1224 <          FState := stInSQL
1225 <      end;
1226 <
1227 <    sqEOL:
1228 <      begin
1229 <        case FState of
1230 <        stInit:
1231 <          {Do nothing};
1232 <        else
1233 <          if NonSpace then AddToSQL(LineEnding);
1234 <        end;
1235 <      end;
1236 <
1237 <    sqEOF:
1238 <      begin
1239 <        Done := true;
1240 <        Result := trim(FSQLText) <> '';
1241 <      end
1242 <    else
1243 <    if FState <> stInit then
1244 <      AddToSQL(Symbol);
1245 <    end
1246 <  end;
1247 <  stmt := FSQLText;
1248 < //  writeln('stmt = ',stmt);
1249 < end;
1250 <
1251 < { TIBXMLProcessor }
1252 <
1253 < procedure TIBXMLProcessor.EndXMLTag(xmltag: TXMLTag);
1254 < begin
1255 <  if FXMLTagIndex = 0 then
1256 <    FSymbolStream.ShowError(sXMLStackUnderflow,[nil]);
1257 <  if xmltag <> FXMLTagStack[FXMLTagIndex] then
1258 <    FSymbolStream.ShowError(sInvalidEndTag,[FSymbolStream.SymbolValue]);
1259 <
1260 <  case FXMLTagStack[FXMLTagIndex] of
1261 <  xtBlob:
1262 <    FBlobData[FCurrentBlob].BlobIntf.Close;
1263 <
1264 <  xtArray:
1265 <    FArrayData[FCurrentArray].ArrayIntf.SaveChanges;
1266 <
1267 <  xtElt:
1268 <    Dec(FArrayData[FCurrentArray].CurrentRow);
1269 <  end;
1270 <  Dec(FXMLTagIndex);
1271 < end;
1272 <
1273 < procedure TIBXMLProcessor.EnterTag;
1274 < var aCharSetID: integer;
1275 < begin
1276 <  case FXMLTagStack[FXMLTagIndex] of
1277 <  xtBlob:
1278 <    begin
1279 <      Database.Connected := true;
1280 <      Transaction.Active := true;
1281 <      FBlobData[FCurrentBlob].BlobIntf := Database.Attachment.CreateBlob(
1282 <        Transaction.TransactionIntf,FBlobData[FCurrentBlob].SubType);
1283 <    end;
1284 <
1285 <  xtArray:
1286 <    with FArrayData[FCurrentArray] do
1287 <    begin
1288 <      Database.Connected := true;
1289 <      Transaction.Active := true;
1290 <      Database.Attachment.CharSetName2CharSetID(CharSet,aCharSetID);
1291 <      SetLength(Index,dim);
1292 <      ArrayIntf := Database.Attachment.CreateArray(
1293 <                     Transaction.TransactionIntf,
1294 <                     Database.Attachment.CreateArrayMetaData(SQLType,
1295 <                       relationName,columnName,Scale,Size,
1296 <                       aCharSetID,dim,bounds)
1297 <                     );
1298 <    end;
1836 >    readln(Line);
1837 >    EchoNextLine(Line);
1838    end;
1839   end;
1840  
1841 < function TIBXMLProcessor.GetArrayData(index: integer): TArrayData;
1303 < begin
1304 <  if (index < 0) or (index > ArrayDataCount) then
1305 <    FSymbolStream.ShowError(sArrayIndexError,[index]);
1306 <  Result := FArrayData[index];
1307 < end;
1308 <
1309 < function TIBXMLProcessor.GetArrayDataCount: integer;
1310 < begin
1311 <  Result := Length(FArrayData);
1312 < end;
1313 <
1314 < function TIBXMLProcessor.GetBlobData(index: integer): TBlobData;
1315 < begin
1316 <  if (index < 0) or (index > BlobDataCount) then
1317 <    FSymbolStream.ShowError(sBlobIndexError,[index]);
1318 <  Result := FBlobData[index];
1319 < end;
1320 <
1321 < function TIBXMLProcessor.GetBlobDataCount: integer;
1841 > function TInteractiveSQLStatementReader.GetChar: char;
1842   begin
1843 <  Result := Length(FBlobData);
1844 < end;
1845 <
1846 < procedure TIBXMLProcessor.ProcessTagValue(tagValue: string);
1327 <
1328 <  function nibble(hex: char): byte;
1329 <  begin
1330 <    case hex of
1331 <    '0': Result := 0;
1332 <    '1': Result := 1;
1333 <    '2': Result := 2;
1334 <    '3': Result := 3;
1335 <    '4': Result := 4;
1336 <    '5': Result := 5;
1337 <    '6': Result := 6;
1338 <    '7': Result := 7;
1339 <    '8': Result := 8;
1340 <    '9': Result := 9;
1341 <    'a','A': Result := 10;
1342 <    'b','B': Result := 11;
1343 <    'c','C': Result := 12;
1344 <    'd','D': Result := 13;
1345 <    'e','E': Result := 14;
1346 <    'f','F': Result := 15;
1347 <    end;
1348 <  end;
1349 <
1350 <  procedure RemoveWhiteSpace(var hexData: string);
1351 <  var i: integer;
1843 >  if Terminated then
1844 >    Result := #0
1845 >  else
1846 >  if FLineIndex > Length(FLine) then
1847    begin
1848 <    {Remove White Space}
1849 <    i := 1;
1850 <    while i <= length(hexData) do
1851 <    begin
1852 <      case hexData[i] of
1358 <      ' ',#9,#10,#13:
1359 <        begin
1360 <          if i < Length(hexData) then
1361 <            Move(hexData[i+1],hexData[i],Length(hexData)-i);
1362 <          SetLength(hexData,Length(hexData)-1);
1363 <        end;
1364 <      else
1365 <        Inc(i);
1366 <      end;
1367 <    end;
1368 <  end;
1369 <
1370 <  procedure WriteToBlob(hexData: string);
1371 <  var i,j : integer;
1372 <      blength: integer;
1373 <      P: PChar;
1848 >    Result := LF;
1849 >    FLineIndex := 0;
1850 >  end
1851 >  else
1852 >  if FLineIndex = 0 then
1853    begin
1854 <    RemoveWhiteSpace(hexData);
1855 <    if odd(length(hexData)) then
1377 <      FSymbolStream.ShowError(sBinaryBlockMustbeEven,[nil]);
1378 <    blength := Length(hexData) div 2;
1379 <    IBAlloc(FBlobBuffer,0,blength);
1380 <    j := 1;
1381 <    P := FBlobBuffer;
1382 <    for i := 1 to blength do
1383 <    begin
1384 <      P^ := char((nibble(hexData[j]) shl 4) or nibble(hexdata[j+1]));
1385 <      Inc(j,2);
1386 <      Inc(P);
1387 <    end;
1388 <    FBlobData[FCurrentBlob].BlobIntf.Write(FBlobBuffer^,blength);
1389 <  end;
1390 <
1391 < begin
1392 <  if tagValue = '' then Exit;
1393 <  case FXMLTagStack[FXMLTagIndex] of
1394 <  xtBlob:
1395 <    WriteToBlob(tagValue);
1396 <
1397 <  xtElt:
1398 <    with FArrayData[FCurrentArray] do
1399 <      ArrayIntf.SetAsString(index,tagValue);
1400 <
1401 <  end;
1402 < end;
1403 <
1404 < procedure TIBXMLProcessor.StartXMLTag(xmltag: TXMLTag);
1405 < begin
1406 <  if FXMLTagIndex > 19 then
1407 <    FSymbolStream.ShowError(sXMLStackOverFlow,[nil]);
1408 <  Inc(FXMLTagIndex);
1409 <  FXMLTagStack[FXMLTagIndex] := xmltag;
1410 <  case xmltag of
1411 <  xtBlob:
1412 <    begin
1413 <      Inc(FCurrentBlob);
1414 <      SetLength(FBlobData,FCurrentBlob+1);
1415 <      FBlobData[FCurrentBlob].BlobIntf := nil;
1416 <      FBlobData[FCurrentBlob].SubType := 0;
1417 <    end;
1418 <
1419 <  xtArray:
1420 <    begin
1421 <      Inc(FCurrentArray);
1422 <      SetLength(FArrayData,FCurrentArray+1);
1423 <      with FArrayData[FCurrentArray] do
1424 <      begin
1425 <        ArrayIntf := nil;
1426 <        SQLType := 0;
1427 <        dim := 0;
1428 <        Size := 0;
1429 <        Scale := 0;
1430 <        CharSet := 'NONE';
1431 <        SetLength(Index,0);
1432 <        CurrentRow := -1;
1433 <      end;
1434 <    end;
1435 <
1436 <  xtElt:
1437 <    with FArrayData[FCurrentArray] do
1438 <      Inc(CurrentRow);
1439 <
1440 <  end;
1441 < end;
1442 <
1443 < procedure TIBXMLProcessor.ProcessAttributeValue(attrValue: string);
1444 < begin
1445 <  case FXMLTagStack[FXMLTagIndex] of
1446 <  xtBlob:
1447 <    if FAttributeName = 'subtype' then
1448 <      FBlobData[FCurrentBlob].SubType := StrToInt(attrValue)
1854 >    if not GetNextLine(FLine) then
1855 >      Result := #0
1856      else
1857 <      FSymbolStream.ShowError(sXMLAttributeError,[FAttributeName,attrValue]);
1858 <
1452 <  xtArray:
1453 <    if FAttributeName = 'sqltype' then
1454 <      FArrayData[FCurrentArray].SQLType := StrToInt(attrValue)
1455 <    else
1456 <    if FAttributeName = 'relation_name' then
1457 <      FArrayData[FCurrentArray].relationName := attrValue
1458 <    else
1459 <    if FAttributeName = 'column_name' then
1460 <      FArrayData[FCurrentArray].columnName := attrValue
1461 <    else
1462 <    if FAttributeName = 'dim' then
1463 <      FArrayData[FCurrentArray].Dim := StrToInt(attrValue)
1464 <    else
1465 <    if FAttributeName = 'length' then
1466 <      FArrayData[FCurrentArray].Size := StrToInt(attrValue)
1467 <    else
1468 <    if FAttributeName = 'scale' then
1469 <      FArrayData[FCurrentArray].Scale := StrToInt(attrValue)
1857 >    if Length(FLine) = 0 then
1858 >      Result := LF
1859      else
1471    if FAttributeName = 'charset' then
1472      FArrayData[FCurrentArray].CharSet := attrValue
1473    else
1474    if FAttributeName = 'bounds' then
1475      ProcessBoundsList(attrValue)
1476    else
1477      FSymbolStream.ShowError(sXMLAttributeError,[FAttributeName,attrValue]);
1478
1479  xtElt:
1480    if FAttributeName = 'ix' then
1481      with FArrayData[FCurrentArray] do
1482        Index[CurrentRow] :=  StrToInt(attrValue)
1483     else
1484        FSymbolStream.ShowError(sXMLAttributeError,[FAttributeName,attrValue]);
1485  end;
1486 end;
1487
1488 procedure TIBXMLProcessor.ProcessBoundsList(boundsList: string);
1489 var list: TStringList;
1490    i,j: integer;
1491 begin
1492  list := TStringList.Create;
1493  try
1494    list.Delimiter := ',';
1495    list.DelimitedText := boundsList;
1496    with FArrayData[FCurrentArray] do
1860      begin
1861 <      if dim <> list.Count then
1862 <        FSymbolStream.ShowError(sInvalidBoundsList,[boundsList]);
1863 <      SetLength(bounds,dim);
1864 <      for i := 0 to list.Count - 1 do
1865 <      begin
1866 <        j := Pos(':',list[i]);
1867 <        if j = 0 then
1868 <          raise Exception.CreateFmt(sInvalidBoundsList,[boundsList]);
1506 <        bounds[i].LowerBound := StrToInt(system.copy(list[i],1,j-1));
1507 <        bounds[i].UpperBound := StrToInt(system.copy(list[i],j+1,length(list[i])-j));
1508 <      end;
1509 <    end;
1510 <  finally
1511 <    list.Free;
1861 >      Result := FLine[1];
1862 >      FLineIndex := 2;
1863 >    end
1864 >  end
1865 >  else
1866 >  begin
1867 >    Result := FLine[FLineIndex];
1868 >    Inc(FLineIndex);
1869    end;
1870   end;
1871  
1872 < constructor TIBXMLProcessor.Create;
1872 > constructor TInteractiveSQLStatementReader.Create(aPrompt: string; aContinue: string);
1873   begin
1874    inherited Create;
1875 <  NextStatement;
1875 >  FPrompt := aPrompt;
1876 >  FLineIndex := 0;
1877 >  FNextStatement := true;
1878 >  FContinuePrompt := aContinue;
1879   end;
1880  
1881 < destructor TIBXMLProcessor.Destroy;
1881 > function TInteractiveSQLStatementReader.GetNextStatement(var stmt: string
1882 >  ): boolean;
1883   begin
1884 <  FreeMem(FBlobBuffer);
1885 <  inherited Destroy;
1884 >  Result := inherited GetNextStatement(stmt);
1885 >  FNextStatement := Result;
1886   end;
1887  
1888 < function TIBXMLProcessor.AnalyseXML(SymbolStream: TSymbolStream): string;
1528 < var Symbol: TSQLSymbol;
1529 <    Done: boolean;
1530 <    XMLString: string;
1531 < begin
1532 <  Result := '';
1533 <  XMLString := '';
1534 <  Done := false;
1535 <  FState := stInTag;
1536 <  FSymbolStream := SymbolStream;
1537 <  with SymbolStream do
1538 <  begin
1539 <    StartXMLTag(XMLTag);
1540 <    while not Done do
1541 <    with SymbolStream do
1542 <    begin
1543 <      Symbol := GetSymbol;
1544 <
1545 <      case Symbol of
1546 <      sqEOL:
1547 <      case FState of
1548 <      stQuotedAttributeValue,
1549 <      stTagged:
1550 <         XMLString += LineEnding;
1551 <      end;
1552 <
1553 <      ' ',sqTab:
1554 <        case FState of
1555 <        stQuotedAttributeValue,
1556 <        stTagged:
1557 <           XMLString += ' ';
1558 <        end;
1559 <
1560 <      ';':
1561 <        case FState of
1562 <        stQuotedAttributeValue,
1563 <        stTagged:
1564 <           XMLString += ';';
1565 <        else
1566 <          ShowError(sXMLError,[Symbol]);
1567 <        end;
1888 > { TBatchSQLStatementReader }
1889  
1890 <      '''':
1570 <        case FState of
1571 <        stQuotedAttributeValue,
1572 <        stTagged:
1573 <           XMLString += '''';
1574 <        else
1575 <          ShowError(sXMLError,[Symbol]);
1576 <        end;
1577 <
1578 <      '*':
1579 <        case FState of
1580 <        stQuotedAttributeValue,
1581 <        stTagged:
1582 <           XMLString += '*';
1583 <        else
1584 <          ShowError(sXMLError,[Symbol]);
1585 <        end;
1586 <
1587 <      '/':
1588 <        case FState of
1589 <        stQuotedAttributeValue,
1590 <        stTagged:
1591 <           XMLString += '/';
1592 <        else
1593 <          ShowError(sXMLError,[Symbol]);
1594 <        end;
1595 <
1596 <      '>':
1597 <        case FState of
1598 <        stEndTag:
1599 <            case XMLTag of
1600 <            xtBlob:
1601 <              begin
1602 <                Result := ':' + Format(ibx_blob+'%d',[FCurrentBlob]);
1603 <                Done := true;
1604 <              end;
1605 <            xtArray:
1606 <              begin
1607 <                Result := ':' + Format(ibx_array+'%d',[FCurrentArray]);
1608 <                Done := true;
1609 <              end;
1610 <            else
1611 <              FState := stTagged;
1612 <          end;
1613 <
1614 <        stInTag:
1615 <          begin
1616 <            XMLString := '';
1617 <            FState := stTagged;
1618 <            EnterTag;
1619 <          end;
1620 <
1621 <        stQuotedAttributeValue,
1622 <        stTagged:
1623 <          XMLString += '>';
1624 <
1625 <        else
1626 <          ShowError(sXMLError,[Symbol]);
1627 <        end;
1628 <
1629 <      sqTag:
1630 <        if FState = stTagged then
1631 <        begin
1632 <          FState := stInTag;
1633 <          StartXMLTag(XMLTag)
1634 <        end
1635 <        else
1636 <          ShowError(sXMLError,[Symbol]);
1637 <
1638 <      sqEndTag:
1639 <        if FState = stTagged then
1640 <        begin
1641 <          ProcessTagValue(XMLString);
1642 <          EndXMLTag(XMLTag);
1643 <          FState := stEndTag;
1644 <        end
1645 <        else
1646 <          ShowError(sXMLError,[Symbol]);
1647 <
1648 <      '=':
1649 <        case FState of
1650 <        stAttribute:
1651 <          FState := stAttributeValue;
1652 <
1653 <        stQuotedAttributeValue,
1654 <        stTagged:
1655 <          XMLString += '=';
1656 <
1657 <        else
1658 <          ShowError(sXMLError,[Symbol]);
1659 <        end;
1660 <
1661 <      '"':
1662 <        case FState of
1663 <        stAttributeValue:
1664 <          begin
1665 <            XMLString := '';
1666 <            FState := stQuotedAttributeValue;
1667 <          end;
1668 <
1669 <        stQuotedAttributeValue:
1670 <          begin
1671 <            ProcessAttributeValue(XMLString);
1672 <            FState := stInTag;
1673 <          end;
1674 <
1675 <        stTagged:
1676 <          XMLString += '"';
1677 <
1678 <        else
1679 <          ShowError(sXMLError,[Symbol]);
1680 <        end;
1681 <
1682 <      sqString:
1683 <        case FState of
1684 <        stInTag: {attribute name}
1685 <          begin
1686 <            FAttributeName := SymbolValue;
1687 <            FState := stAttribute;
1688 <          end;
1689 <
1690 <        stAttributeValue:
1691 <          begin
1692 <            ProcessAttributeValue(FString);
1693 <            FState := stInTag;
1694 <          end;
1695 <
1696 <        stQuotedAttributeValue,
1697 <        stTagged:
1698 <           XMLString += SymbolValue;
1699 <
1700 <        else
1701 <          ShowError(sXMLError,[Symbol]);
1702 <        end;
1703 <      else
1704 <        ShowError(sXMLError,[Symbol]);
1705 <      end
1706 <    end;
1707 <  end;
1708 < end;
1709 <
1710 < procedure TIBXMLProcessor.NextStatement;
1711 < begin
1712 <  FXMLTagIndex := 0;
1713 <  SetLength(FBlobData,0);
1714 <  FCurrentBlob := -1;
1715 <  SetLength(FArrayData,0);
1716 <  FCurrentArray := -1;
1717 < end;
1718 <
1719 < class function TIBXMLProcessor.FormatBlob(Field: ISQLData): string;
1720 < var TextOut: TStrings;
1890 > function TBatchSQLStatementReader.GetChar: char;
1891   begin
1892 <  TextOut := TStringList.Create;
1893 <  try
1894 <    TextOut.Add(Format('<blob subtype="%d">',[Field.getSubtype]));
1895 <    StringToHex(Field.AsString,TextOut,BlobLineLength);
1726 <    TextOut.Add('</blob>');
1727 <    Result := TextOut.Text;
1728 <  finally
1729 <    TextOut.Free;
1730 <  end;
1731 < end;
1732 <
1733 < class function TIBXMLProcessor.FormatArray(Database: TIBDatabase; ar: IArray
1734 <  ): string;
1735 < var index: array of integer;
1736 <    TextOut: TStrings;
1737 <
1738 <    procedure AddElements(dim: integer; indent:string = ' ');
1739 <    var i: integer;
1740 <        recurse: boolean;
1892 >  if not EOF and assigned(FInStream) and not (FInStream.Position = FInStream.Size) then
1893 >  begin
1894 >    Result := char(FInStream.ReadByte);
1895 >    if Result = LF then
1896      begin
1897 <      SetLength(index,dim+1);
1898 <      recurse := dim < ar.GetDimensions - 1;
1899 <      with ar.GetBounds[dim] do
1900 <      for i := LowerBound to UpperBound do
1901 <      begin
1902 <        index[dim] := i;
1903 <        if recurse then
1904 <        begin
1905 <          TextOut.Add(Format('%s<elt id="%d">',[indent,i]));
1751 <          AddElements(dim+1,indent + ' ');
1752 <          TextOut.Add('</elt>');
1753 <        end
1754 <        else
1755 <        if ((ar.GetSQLType = SQL_TEXT) or (ar.GetSQLType = SQL_VARYING)) and
1756 <           (ar.GetCharSetID = 1) then
1757 <           TextOut.Add(Format('%s<elt ix="%d">%s</elt>',[indent,i,StringToHex(ar.GetAsString(index))]))
1758 <        else
1759 <          TextOut.Add(Format('%s<elt ix="%d">%s</elt>',[indent,i,ar.GetAsString(index)]));
1760 <      end;
1761 <    end;
1762 <
1763 < var
1764 <    s: string;
1765 <    bounds: TArrayBounds;
1766 <    i: integer;
1767 <    boundsList: string;
1768 < begin
1769 <  TextOut := TStringList.Create;
1770 <  try
1771 <    s := Format('<array dim = "%d" sqltype = "%d" length = "%d" relation_name = "%s" column_name = "%s"',
1772 <                                [ar.GetDimensions,ar.GetSQLType,ar.GetSize,
1773 <                                 ar.GetTableName,ar.GetColumnName]);
1774 <    case ar.GetSQLType of
1775 <    SQL_DOUBLE, SQL_FLOAT, SQL_LONG, SQL_SHORT, SQL_D_FLOAT, SQL_INT64:
1776 <       s += Format(' scale = "%d"',[ ar.GetScale]);
1777 <    SQL_TEXT,
1778 <    SQL_VARYING:
1779 <      s += Format(' charset = "%s"',[Database.Attachment.GetCharsetName(ar.GetCharSetID)]);
1780 <    end;
1781 <    bounds := ar.GetBounds;
1782 <    boundsList := '';
1783 <    for i := 0 to length(bounds) - 1 do
1897 >      EchoNextLine(FCurLine);
1898 >      FCurLine := '';
1899 >      if assigned(OnProgressEvent) then
1900 >        OnProgressEvent(self,false,FIndex+1);
1901 >      Inc(FLineIndex);
1902 >      FIndex := 1;
1903 >    end
1904 >    else
1905 >    if Result <> CR then
1906      begin
1907 <      if i <> 0 then boundsList += ',';
1908 <      boundsList += Format('%d:%d',[bounds[i].LowerBound,bounds[i].UpperBound]);
1907 >      FCurLine += Result;
1908 >      Inc(FIndex);
1909      end;
1910 <    s += Format(' bounds="%s"',[boundsList]);
1789 <    s += '>';
1790 <    TextOut.Add(s);
1791 <
1792 <    SetLength(index,0);
1793 <    AddElements(0);
1794 <    TextOut.Add('</array>');
1795 <    Result := TextOut.Text;
1796 <  finally
1797 <    TextOut.Free;
1798 <  end;
1799 < end;
1800 <
1801 < { TInteractiveSymbolStream }
1802 <
1803 < function TInteractiveSymbolStream.GetErrorPrefix: string;
1804 < begin
1805 <  Result := '';
1806 < end;
1807 <
1808 < function TInteractiveSymbolStream.GetNextLine(var Line: string): boolean;
1809 < begin
1810 <  if FNextStatement then
1811 <    write(FPrompt)
1812 <  else
1813 <    write(FContinuePrompt);
1814 <  Result := not EOF;
1815 <  if Result then
1816 <    readln(Line);
1817 < end;
1818 <
1819 < constructor TInteractiveSymbolStream.Create(aPrompt: string; aContinue: string);
1820 < begin
1821 <  inherited Create;
1822 <  FPrompt := aPrompt;
1823 <  FContinuePrompt := aContinue;
1824 < end;
1825 <
1826 < function TInteractiveSymbolStream.GetSymbol: TSQLSymbol;
1827 < begin
1828 <  if Terminated then
1829 <    Result := sqEOF
1910 >  end
1911    else
1912 <    Result := inherited GetSymbol;
1912 >    Result := #0;
1913   end;
1914  
1915 < { TBatchSymbolStream }
1835 <
1836 < function TBatchSymbolStream.GetErrorPrefix: string;
1915 > function TBatchSQLStatementReader.GetErrorPrefix: string;
1916   begin
1917    Result := Format(sOnLineError,[FLineIndex,FIndex]);
1918   end;
1919  
1920 < function TBatchSymbolStream.GetNextLine(var Line: string): boolean;
1842 < begin
1843 <  Result := FLineIndex < FLines.Count;
1844 <  if Result then
1845 <  begin
1846 <    Line := FLines[FLineIndex];
1847 < //    writeln('Next Line = ',Line);
1848 <    Inc(FLineIndex);
1849 <    if assigned(OnProgressEvent) then
1850 <      OnProgressEvent(self,false,1);
1851 <  end;
1852 < end;
1853 <
1854 < constructor TBatchSymbolStream.Create;
1920 > procedure TBatchSQLStatementReader.Reset;
1921   begin
1922 <  inherited Create;
1923 <  FLines := TStringList.Create;
1924 < end;
1925 <
1926 < destructor TBatchSymbolStream.Destroy;
1927 < begin
1928 <  if assigned(FLines) then FLines.Free;
1929 <  inherited Destroy;
1930 < end;
1931 <
1932 < procedure TBatchSymbolStream.SetStreamSource(Lines: TStrings);
1933 < begin
1934 <  FLineIndex := 0;
1935 <  FLines.Assign(Lines);
1922 >  inherited Reset;
1923 >  if FOwnsInStream and assigned(FInStream) then
1924 >    FInStream.Free;
1925 >  FInStream := nil;
1926 >  FOwnsInStream := false;
1927 >  FLineIndex := 1;
1928 >  FIndex := 1;
1929 >  FCurLine := '';
1930 > end;
1931 >
1932 > procedure TBatchSQLStatementReader.SetStreamSource(Lines: TStrings);
1933 > begin
1934 >  Reset;
1935 >  FInStream := TMemoryStream.Create;
1936 >  FOwnsInStream := true;
1937 >  Lines.SaveToStream(FInStream);
1938 >  FInStream.Position := 0;
1939    if assigned(OnProgressEvent) then
1940 <    OnProgressEvent(self,true,FLines.Count);
1940 >    OnProgressEvent(self,true,FInStream.Size);
1941   end;
1942  
1943 < procedure TBatchSymbolStream.SetStreamSource(S: TStream);
1943 > procedure TBatchSQLStatementReader.SetStreamSource(S: TStream);
1944   begin
1945 <  FLineIndex := 0;
1946 <  FLines.LoadFromStream(S);
1945 >  Reset;
1946 >  FInStream := S;
1947    if assigned(OnProgressEvent) then
1948 <    OnProgressEvent(self,true,FLines.Count);
1948 >    OnProgressEvent(self,true,S.Size - S.Position);
1949   end;
1950  
1951 < procedure TBatchSymbolStream.SetStreamSource(FileName: string);
1951 > procedure TBatchSQLStatementReader.SetStreamSource(FileName: string);
1952   begin
1953 <  FLineIndex := 0;
1954 <  FLines.LoadFromFile(FileName);
1953 >  Reset;
1954 >  FInStream := TFileStream.Create(FileName,fmShareCompat);
1955 >  FOwnsInStream := true;
1956    if assigned(OnProgressEvent) then
1957 <    OnProgressEvent(self,true,FLines.Count);
1957 >    OnProgressEvent(self,true,FInStream.Size);
1958   end;
1959  
1960 < { TSymbolStream }
1891 <
1892 < function TSymbolStream.GetNextSymbol(C: char): TSQLSymbol;
1893 < begin
1894 <  Result := sqNone;
1895 <  if C = FTerminator then
1896 <    Result := sqTerminator
1897 <  else
1898 <  case C of
1899 <  #0..#8,#10..#31,' ':
1900 <    Result := ' ';
1901 <
1902 <  #9,';','"','''','/','-',
1903 <  '*','=','>','<',',':
1904 <    Result := C;
1905 <  else
1906 <    begin
1907 <      Result := sqString;
1908 <      FLastChar := C
1909 <    end
1910 <  end;
1911 < end;
1912 <
1913 < function TSymbolStream.FindTag(tag: string; var xmlTag: TXMLTag): boolean;
1914 < var i: integer;
1915 < begin
1916 <  Result := false;
1917 <  for i := 0 to Length(XMLTagDefs) - 1 do
1918 <    if XMLTagDefs[i].TagValue = tag then
1919 <    begin
1920 <      xmlTag := XMLTagDefs[i].XMLTag;
1921 <      Result := true;
1922 <      break;
1923 <    end;
1924 < end;
1925 <
1926 < constructor TSymbolStream.Create;
1960 > procedure TBatchSQLStatementReader.SetStringStreamSource(S: string);
1961   begin
1962 <  inherited;
1963 <  FTerminator := DefaultTerminator;
1964 <  NextStatement;
1965 < end;
1966 <
1933 < procedure TSymbolStream.ShowError(msg: string; params: array of const);
1934 < begin
1935 <  raise EIBClientError.CreateFmt(GetErrorPrefix + msg,params);
1936 < end;
1937 <
1938 < function TSymbolStream.GetSymbol: TSQLSymbol;
1939 < var
1940 <    DelimitedText: string;
1941 <    CurState: (gsNone,gsInComment,gsInSingleQuotes,gsInDoubleQuotes);
1942 < begin
1943 <  Result := sqNone;
1944 <  CurState := gsNone;
1945 <  DelimitedText := '';
1946 <  if FNextSymbol <> sqNone then
1947 <  begin
1948 <    Result := FNextSymbol;
1949 <    if Result = sqString then
1950 <      FString := FLastChar
1951 <    else
1952 <      FString := '';
1953 <    FNextSymbol := sqNone
1954 <  end;
1955 <
1956 <  while FNextSymbol = sqNone do {find the next symbol}
1957 <  begin
1958 <    if FIndex > Length(FLine) then
1959 <    begin
1960 <      FNextSymbol := sqEOL;
1961 <      FIndex := 0;
1962 <    end
1963 <    else
1964 <    begin
1965 <      if FIndex = 0 then
1966 <      begin
1967 <        if not GetNextLine(FLine) then
1968 <        begin
1969 <          Result := sqEOF;
1970 <          FNextSymbol := sqNone;
1971 <          Exit;
1972 <        end;
1973 <        FIndex := 1;
1974 <        FNextStatement := false;
1975 <        if assigned(OnNextLine) then
1976 <          OnNextLine(self,FLine);
1977 <        if CurState <> gsNone then
1978 <          DelimitedText += LineEnding;
1979 <        if Length(FLine) = 0 then
1980 <          continue;
1981 <      end;
1982 <      if CurState <> gsNone then
1983 <        DelimitedText += FLine[FIndex];
1984 <      FNextSymbol := GetNextSymbol(FLine[FIndex]);
1985 <      Inc(FIndex);
1986 <    end;
1987 <
1988 <    case CurState of
1989 <    gsNone:
1990 <      begin
1991 <        {combine if possible}
1992 <        case Result of
1993 <        sqNone:
1994 <          begin
1995 <            Result := FNextSymbol;
1996 <            if FNextSymbol = sqString then
1997 <              FString := FLastChar;
1998 <            FNextSymbol := sqNone
1999 <          end;
2000 <
2001 <        '/':
2002 <          if FXMLMode > 0 then
2003 <            break
2004 <          else
2005 <          if FNextSymbol = '*' then
2006 <          begin
2007 <            CurState := gsInComment;
2008 <            DelimitedText := '/*';
2009 <            Result := sqNone;
2010 <            FNextSymbol := sqNone
2011 <          end
2012 <          else
2013 <          if FNextSymbol = '/' then
2014 <          begin
2015 <            FString := '/*' + system.copy(FLine,FIndex,length(FLine)- FIndex + 1) + ' */';
2016 <            Result := sqCommentLine;
2017 <            FIndex := 0;
2018 <            FNextSymbol := sqNone
2019 <          end;
2020 <
2021 <        '-':
2022 <          if FXMLMode > 0 then
2023 <            break
2024 <          else
2025 <          if FNextSymbol = '-' then
2026 <          begin
2027 <            FString := '--' + system.copy(FLine,FIndex,length(FLine)- FIndex + 1) ;
2028 <            Result := sqCommentLine;
2029 <            FIndex := 0;
2030 <            FNextSymbol := sqNone
2031 <          end;
2032 <
2033 <        '<':
2034 <          if (FXMLMode > 0) and (FNextSymbol = '/') then
2035 <          begin
2036 <            Result := sqEndTag;
2037 <            FString := '';
2038 <            FNextSymbol := sqNone
2039 <          end
2040 <          else
2041 <          if FNextSymbol = sqString then
2042 <          begin
2043 <            Result := sqTag;
2044 <            FString := FLastChar;
2045 <            FNextSymbol := sqNone
2046 <          end;
2047 <
2048 <        '''':
2049 <        if FXMLMode > 0 then
2050 <          break
2051 <        else
2052 <        if FNextSymbol = '''' then
2053 <        begin
2054 <          Result := sqQuotedString;
2055 <          FString := '''''';
2056 <          FNextSymbol := sqNone
2057 <        end
2058 <        else
2059 <        begin
2060 <          CurState := gsInSingleQuotes;
2061 <          DelimitedText := '''';
2062 <          if FNextSymbol = sqEOL then
2063 <            DelimitedText += LineEnding
2064 <          else
2065 <            DelimitedText += FLine[FIndex-1];
2066 <          Result := sqNone;
2067 <          FNextSymbol := sqNone
2068 <        end;
2069 <
2070 <        '"':
2071 <        if FXMLMode > 0 then
2072 <          break
2073 <        else
2074 <        begin
2075 <          CurState := gsInDoubleQuotes;
2076 <          DelimitedText := '"';
2077 <          if FNextSymbol = sqEOL then
2078 <            DelimitedText += LineEnding
2079 <          else
2080 <            DelimitedText += FLine[FIndex-1];
2081 <          Result := sqNone;
2082 <          FNextSymbol := sqNone
2083 <        end;
2084 <
2085 <        sqTag,
2086 <        sqEndTag,
2087 <        sqString:
2088 <          if FNextSymbol = sqString then
2089 <          begin
2090 <            FString := FString + FLastChar;
2091 <            FNextSymbol := sqNone
2092 <          end;
2093 <        end
2094 <      end;
2095 <
2096 <    {Check for state exit condition}
2097 <    gsInSingleQuotes:
2098 <      if Result = '''' then
2099 <      begin
2100 <         CurState := gsNone;
2101 <         if FNextSymbol = sqEOL then
2102 <           FString := DelimitedText
2103 <         else
2104 <           FString := system.copy(DelimitedText,1,Length(DelimitedText)-1);
2105 <         Result := sqQuotedString;
2106 <       end;
2107 <
2108 <    gsInDoubleQuotes:
2109 <      if Result = '"' then
2110 <      begin
2111 <         CurState := gsNone;
2112 <         if FNextSymbol = sqEOL then
2113 <           FString := DelimitedText
2114 <         else
2115 <           FString := system.copy(DelimitedText,1,Length(DelimitedText)-1);
2116 <         Result := sqDoubleQuotedString;
2117 <       end;
2118 <
2119 <    gsInComment:
2120 <    if (Result = '*') and (FNextSymbol = '/') then
2121 <      begin
2122 <        CurState := gsNone;
2123 <        FString := DelimitedText;
2124 <        Result := sqComment;
2125 <        FNextSymbol := sqNone
2126 <      end;
2127 <
2128 <    end;
2129 <
2130 <    if (CurState <> gsNone) and (FNextSymbol <> sqNone) then
2131 <    begin
2132 <      Result := FNextSymbol;
2133 <      FNextSymbol := sqNone;
2134 <    end;
2135 <  end;
2136 <
2137 <  if (Result = sqTag) and (FNextSymbol <> sqNone) then
2138 <  begin
2139 <    if FindTag(FString,FXMLTag) then
2140 <      Inc(FXMLMode)
2141 <    else
2142 <      Result := sqString;
2143 <  end
2144 <  else
2145 <  if (Result = sqEndTag) and (FNextSymbol <> sqNone) then
2146 <  begin
2147 <    if FindTag(FString,FXMLTag) then
2148 <      Dec(FXMLMode)
2149 <    else
2150 <      Result := sqString;
2151 <  end;
2152 <
2153 <  if (FXMLMode = 0) and (Result = sqString) and (FString <> '') then
2154 <  begin
2155 <       if CompareText(FString,'begin') = 0 then
2156 <         Result := sqBegin
2157 <       else
2158 <       if CompareText(FString,'end') = 0 then
2159 <         Result := sqEnd
2160 <       else
2161 <       if CompareText(FString,'declare') = 0 then
2162 <         Result := sqDeclare
2163 <       else
2164 <       if CompareText(FString,'case') = 0 then
2165 <         Result := sqCase
2166 <  end;
2167 < //  writeln(Result,',',FString);
2168 < end;
2169 <
2170 < procedure TSymbolStream.NextStatement;
2171 < begin
2172 <  FXMLTag := xtNone;
2173 <  FNextStatement := true;
1962 >  Reset;
1963 >  FInStream := TStringStream.Create(S);
1964 >  FOwnsInStream := true;
1965 >  if assigned(OnProgressEvent) then
1966 >    OnProgressEvent(self,true,FInStream.Size);
1967   end;
1968  
1969   end.

Comparing ibx/trunk/runtime/nongui/ibxscript.pas (property svn:eol-style):
Revision 229 by tony, Tue Apr 10 13:32:36 2018 UTC vs.
Revision 380 by tony, Mon Jan 10 10:13:17 2022 UTC

# Line 0 | Line 1
1 + native

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines