~ubuntu-branches/ubuntu/wily/tora/wily-proposed

« back to all changes in this revision

Viewing changes to src/tosqlparse.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Albin Tonnerre
  • Date: 2007-05-29 13:13:36 UTC
  • mfrom: (1.2.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070529131336-85ygaddivvmkd3xc
Tags: 1.3.21pre22-1ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
  - debian/rules: call dh_iconcache
  - Remove g++ build dependency
* Modify Maintainer value to match Debian-Maintainer-Field Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****
 
2
*
 
3
* TOra - An Oracle Toolkit for DBA's and developers
 
4
* Copyright (C) 2003-2005 Quest Software, Inc
 
5
* Portions Copyright (C) 2005 Other Contributors
 
6
 
7
* This program is free software; you can redistribute it and/or
 
8
* modify it under the terms of the GNU General Public License
 
9
* as published by the Free Software Foundation;  only version 2 of
 
10
* the License is valid for this program.
 
11
 
12
* This program is distributed in the hope that it will be useful,
 
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
* GNU General Public License for more details.
 
16
 
17
* You should have received a copy of the GNU General Public License
 
18
* along with this program; if not, write to the Free Software
 
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
20
*
 
21
*      As a special exception, you have permission to link this program
 
22
*      with the Oracle Client libraries and distribute executables, as long
 
23
*      as you follow the requirements of the GNU GPL in regard to all of the
 
24
*      software in the executable aside from Oracle client libraries.
 
25
*
 
26
*      Specifically you are not permitted to link this program with the
 
27
*      Qt/UNIX, Qt/Windows or Qt Non Commercial products of TrollTech.
 
28
*      And you are not permitted to distribute binaries compiled against
 
29
*      these libraries without written consent from Quest Software, Inc.
 
30
*      Observe that this does not disallow linking to the Qt Free Edition.
 
31
*
 
32
*      You may link this product with any GPL'd Qt library such as Qt/Free
 
33
*
 
34
* All trademarks belong to their respective owners.
 
35
*
 
36
*****/
 
37
 
 
38
#include "utils.h"
 
39
 
 
40
#include "toconnection.h"
 
41
#include "tohighlightedtext.h"
 
42
#include "tosqlparse.h"
 
43
 
 
44
#include <qapplication.h>
 
45
#include <qstringlist.h>
 
46
 
 
47
#ifdef TOPARSE_DEBUG
 
48
 
 
49
#include <stdio.h>
 
50
 
 
51
bool toMonolithic(void)
 
52
{
 
53
    return false;
 
54
}
 
55
 
 
56
void printStatement(toSQLParse::statement &stat, int level)
 
57
{
 
58
    for (int i = 0;i < level;i++)
 
59
        printf(" ");
 
60
 
 
61
    switch (stat.Type)
 
62
    {
 
63
    case toSQLParse::statement::Block:
 
64
        printf("Block:");
 
65
        break;
 
66
    case toSQLParse::statement::Statement:
 
67
        printf("Statement:");
 
68
        break;
 
69
    case toSQLParse::statement::List:
 
70
        printf("List:");
 
71
        break;
 
72
    case toSQLParse::statement::Keyword:
 
73
        printf("Keyword:");
 
74
        break;
 
75
    case toSQLParse::statement::Token:
 
76
        printf("Token:");
 
77
        break;
 
78
    case toSQLParse::statement::Raw:
 
79
        printf("Raw:");
 
80
        break;
 
81
    }
 
82
    printf("%s (%d)\n", (const char *)stat.String, stat.Line);
 
83
    if (!stat.Comment.isNull())
 
84
    {
 
85
        for (int i = 0;i < level;i++)
 
86
            printf(" ");
 
87
        printf("Comment:%s\n", (const char *)stat.Comment);
 
88
    }
 
89
    for (std::list<toSQLParse::statement>::iterator i = stat.subTokens().begin();
 
90
            i != stat.subTokens().end();
 
91
            i++)
 
92
        printStatement(*i, level + 1);
 
93
}
 
94
 
 
95
int main(int argc, char **argv)
 
96
{
 
97
    QString res = "\n"
 
98
                  "create table test ( col varchar(12) );\n"
 
99
                  "insert into prova3 (prova)\n"
 
100
                  "values ('This insert contains a ''\n"
 
101
                  "and now it goes to new line');\n"
 
102
                  "create or replace PROCEDURE prova1\n"
 
103
                  "is\n"
 
104
                  "v_tmp NUMBER(1);\n"
 
105
                  "begin\n"
 
106
                  "begin\n"
 
107
                  "select 0 into v_tmp from dual;\n"
 
108
                  "exception\n"
 
109
                  "when 1 = 1 then\n"
 
110
                  "    v_tmp := 'Dadum';\n"
 
111
                  "when others then\n"
 
112
                  "if sqlcode=0 then\n"
 
113
                  "null;\n"
 
114
                  "else\n"
 
115
                  "null;\n"
 
116
                  "end if;\n"
 
117
                  "end;\n"
 
118
                  "\n"
 
119
                  "if v_tmp=0 then\n"
 
120
                  "null;\n"
 
121
                  "end if;\n"
 
122
                  "end;"
 
123
                  "comment on column prova1.prova1 is 'This comment is\n"
 
124
                  "on more than one line';\n"
 
125
                  "PACKAGE oasSIMActivation AS\n"
 
126
                  " FUNCTION ParseCommand(Command VARCHAR2,inICC VARCHAR2,Param VARCHAR2) RETURN VARCHAR2;\n"
 
127
                  "\n"
 
128
                  " PROCEDURE InsertActions(inCommandType VARCHAR2,\n"
 
129
                  "    Sim oasSIM%ROWTYPE,\n"
 
130
                  "    inParam VARCHAR2);\n"
 
131
                  "\n"
 
132
                  " PROCEDURE InsertActions(CommandType VARCHAR2,\n"
 
133
                  "    inICC VARCHAR2,\n"
 
134
                  "    inParam VARCHAR2);\n"
 
135
                  "\n"
 
136
                  " PROCEDURE InsertActions(inCommandType VARCHAR2,\n"
 
137
                  "    Service oasService%ROWTYPE);\n"
 
138
                  "\n"
 
139
                  " PROCEDURE InsertActions(CommandType VARCHAR2,\n"
 
140
                  "    inCustomerID NUMBER,\n"
 
141
                  "    inSubID NUMBER,\n"
 
142
                  "    inServiceType VARCHAR2,\n"
 
143
                  "    Param VARCHAR2);\n"
 
144
                  "END;\n"
 
145
                  "DECLARE\n"
 
146
                  "grade CHAR(1);\n"
 
147
                  "appraisal VARCHAR2(20);\n"
 
148
                  "BEGIN\n"
 
149
                  "CASE grade\n"
 
150
                  "WHEN 'A' THEN 'Excellent'\n"
 
151
                  "WHEN 'B' THEN 'Very Good'\n"
 
152
                  "WHEN 'C' THEN 'Good'\n"
 
153
                  "WHEN 'D' THEN 'Fair'\n"
 
154
                  "WHEN 'F' THEN 'Poor'\n"
 
155
                  "ELSE 'No such grade'\n"
 
156
                  "END;\n"
 
157
                  "IF appraisal IS NULL THEN\n"
 
158
                  "NULL;\n"
 
159
                  "END IF;\n"
 
160
                  "END;\n"
 
161
                  "\n"
 
162
                  "BEGIN\n"
 
163
                  "IF 1 == 1 THEN\n"
 
164
                  "NULL;\n"
 
165
                  "END IF;\n"
 
166
                  "IF appraisal IS NULL THEN\n"
 
167
                  "NULL;\n"
 
168
                  "ELSE\n"
 
169
                  "SELECT CASE WHEN dummy='X' THEN 'A' ELSE 'B' END,  2 FROM dual;\n"
 
170
                  "END IF;\n"
 
171
                  "END;\n"
 
172
                  "\n"
 
173
                  "select count(case when dummy = 'Y' then dummy\n"
 
174
                  "             else null end) as tot_str\n"
 
175
                  "from dual;\n"
 
176
                  "\n"
 
177
                  "SET TRANSACTION READ ONLY\n"
 
178
                  "\n"
 
179
                  "PROMPT Hello\n"
 
180
                  "\n"
 
181
                  "/* Test comment\n"
 
182
                  "*/\n"
 
183
                  "INSERT INTO cdrProcess(ProcessID,\n"
 
184
                  "         StartDate,\n"
 
185
                  "         EnvDate,\n"
 
186
                  "         ProgramID,\n"
 
187
                  "         OSUser,\n"
 
188
                  "         SystemUser,\n"
 
189
                  "         ExecName,\n"
 
190
                  "         ExecVersion,\n"
 
191
                  "         ExecParameters,\n"
 
192
                  "         HostName)\n"
 
193
                  "VALUES (:1,\n"
 
194
                  " SYSDATE,\n"
 
195
                  " SYSDATE,\n"
 
196
                  " :2,\n"
 
197
                  " :3,\n"
 
198
                  " :4,\n"
 
199
                  " :5,\n"
 
200
                  " :6,\n"
 
201
                  " :7,\n"
 
202
                  " :8);\n"
 
203
                  "\n"
 
204
                  "CREATE or REPLACE Procedure TEST_SPR\n"
 
205
                  "(\n"
 
206
                  "    IN_TICKET_NUM   IN  VARCHAR2\n"
 
207
                  ")\n"
 
208
                  "IS\n"
 
209
                  "\n"
 
210
                  "BEGIN\n"
 
211
                  "\n"
 
212
                  "BEGIN\n"
 
213
                  "\n"
 
214
                  "for cur_rec in (select emp_id from employees) loop\n"
 
215
                  "\n"
 
216
                  " update employees set emp_id = emp_id + 1\n"
 
217
                  " where emp_id = cur_rec.emp_id;\n"
 
218
                  " commit;\n"
 
219
                  "end loop;\n"
 
220
                  " \n"
 
221
                  "END;\n"
 
222
                  "END TEST_SPR;\n"
 
223
                  "\n"
 
224
                  "SELECT owner,\n"
 
225
                  "       OBJECT,\n"
 
226
                  "       TYPE FROM v$access\n"
 
227
                  " WHERE sid=:f1<char[101]>\n"
 
228
                  " ORDER BY owner,\n"
 
229
                  "   OBJECT,\n"
 
230
                  "   TYPE;\n"
 
231
                  "\n"
 
232
                  "CREATE TABLE ess.EssCalLog (\n"
 
233
                  "        CalID  CHAR(5) NOT NULL,  -- Calender type\n"
 
234
                  " SeqID  NUMBER(8) NOT NULL,\n"
 
235
                  " ActStt  CHAR(1) NOT NULL\n"
 
236
                  "  CONSTRAINT EssCalLog_CK_ActStt CHECK (ActStt IN ('A','D') ),\n"
 
237
                  " LogRun  CHAR(1) NOT NULL  -- Should runs of this type be logged\n"
 
238
                  "  CONSTRAINT EssCalLog_CK_LogRun CHECK (LogRun IN ('Y','N') ),\n"
 
239
                  " PrcID  NUMBER(8) NOT NULL\n"
 
240
                  "  CONSTRAINT EssCalDay_FK_PrcID REFERENCES ess.EssPrc(PrcID),\n"
 
241
                  " Dsc  VARCHAR2(4000) NOT NULL, -- Description of this type\n"
 
242
                  " CONSTRAINT EssCal_PK PRIMARY KEY (CalID,SeqID)\n"
 
243
                  "  USING INDEX TABLESPACE Index02 -- A Comment\n"
 
244
                  ");\n"
 
245
                  "-- Another comment\n"
 
246
                  "\n"
 
247
                  "CREATE OR REPLACE procedure spTuxGetAccData (oRet                        OUT  NUMBER,\n"
 
248
                  "          oNumSwt                     OUT  NUMBER)\n"
 
249
                  "IS\n"
 
250
                  "  vYear  CHAR(4);\n"
 
251
                  "BEGIN\n"
 
252
                  "    <<label>>\n"
 
253
                  "    DECLARE\n"
 
254
                  "      oTrdStt NUMBER;\n"
 
255
                  "    BEGIN\n"
 
256
                  "      oTrdStt := 0;\n"
 
257
                  "    END;\n"
 
258
                  "\n"
 
259
                  "    EXCEPTION\n"
 
260
                  "        WHEN VALUE_ERROR THEN\n"
 
261
                  "     oRet := 3;\n"
 
262
                  " WHEN NO_DATA_FOUND THEN\n"
 
263
                  "     oRet := 2;\n"
 
264
                  " WHEN OTHERS THEN\n"
 
265
                  "     oRet := 1;\n"
 
266
                  "END;\n"
 
267
                  "CREATE OR REPLACE procedure spTuxGetAccData as\n"
 
268
                  "  vYear  CHAR(4);\n"
 
269
                  "begin\n"
 
270
                  "  null;\n"
 
271
                  "end;\n"
 
272
                  "-------------------------------------------------------------------\n"
 
273
                  "--    EssCal, Current calendar view\n"
 
274
                  "\n"
 
275
                  "CREATE VIEW ess.EssCal AS\n"
 
276
                  "        SELECT CalID,\n"
 
277
                  "        LogRun,\n"
 
278
                  "        PrcID,\n"
 
279
                  "        Dsc\n"
 
280
                  "   FROM ess.EssCalLog a\n"
 
281
                  "  WHERE SeqID = (SELECT MAX(aa.SeqID) FROM EssCalLog aa WHERE aa.CalID = a.CalID)\n"
 
282
                  "    AND ActStt = 'A';\n"
 
283
                  "\n"
 
284
                  "    /* A little comment\n"
 
285
                  "     */\n"
 
286
                  "    SELECT /*+\n"
 
287
                  "FULL(a)\n"
 
288
                  "*/ a.TskCod TskCod -- Test comment\n"
 
289
                  "      ,a.CreEdt CreEdt,\n"
 
290
                  "       a.TspActOprID /* One comment OprID */ , -- Another comment\n"
 
291
                  "       COUNT(1) Tot,\n"
 
292
                  "       COUNT(a.TspActOprID) Lft,\n"
 
293
                  "       b.TraCod TraCod,\n"
 
294
                  "       SUM(b.FinAmt) FinAmt,\n"
 
295
                  "       TraCod\n"
 
296
                  "  FROM EssTsk a,EssTra b\n"
 
297
                  " WHERE ((a.TspActOprID = 'Test') OR a.TspActOprID IS NULL)\n"
 
298
                  "   AND DECODE(a.TspActOprID,NULL,NULL,a.TskID) = b.TskID(+)\n"
 
299
                  " GROUP BY a.TskCod,a.CreEdt,a.TspActOprID,b.TraCod\n"
 
300
                  "HAVING COUNT(a.TspActOprID) > 0;\n"
 
301
                  "SELECT a.Sid \"-Id\",\n"
 
302
                  "       a.Serial# \"-Serial#\",\n"
 
303
                  "       a.SchemaName \"Schema\",\n"
 
304
                  "       a.Status \"Status\",\n"
 
305
                  "       a.Server \"Server\",\n"
 
306
                  "       a.OsUser \"Osuser\",\n"
 
307
                  "       a.Machine \"Machine\",\n"
 
308
                  "       a.Program \"Program\",\n"
 
309
                  "       a.Type \"Type\",\n"
 
310
                  "       a.Module \"Module\",\n"
 
311
                  "       a.Action \"Action\",\n"
 
312
                  "       a.Client_Info \"Client Info\",\n"
 
313
                  "       b.Block_Gets \"-Block Gets\",\n"
 
314
                  "       b.Consistent_Gets \"-Consistent Gets\",\n"
 
315
                  "       b.Physical_Reads \"-Physical Reads\",\n"
 
316
                  "       b.Block_Changes \"-Block Changes\",\n"
 
317
                  "       b.Consistent_Changes \"-Consistent Changes\",\n"
 
318
                  "       c.Value*10 \"-CPU (ms)\",\n"
 
319
                  "       a.Process \"-Process\",\n"
 
320
                  "       a.SQL_Address||':'||SQL_Hash_Value \" SQL Address\",\n"
 
321
                  "       a.Prev_SQL_Addr||':'||Prev_Hash_Value \" Prev SQl Address\"\n"
 
322
                  "  FROM v$session a,\n"
 
323
                  "       v$sess_io b,\n"
 
324
                  "       v$sesstat c\n"
 
325
                  " WHERE a.sid = b.sid(+)\n"
 
326
                  "   AND a.sid = c.sid(+) AND (c.statistic# = 12 OR c.statistic# IS NULL)\n"
 
327
                  " ORDER BY a.Sid;\n"
 
328
                  "select a.TskCod TskCod,\n"
 
329
                  "       count(1) Tot\n"
 
330
                  "  from (select * from EssTsk where PrsID >= '1940') ,EssTra b\n"
 
331
                  " where decode(a.TspActOprID,NULL,NULL,a.PrsID)+5 = b.PrsID(+)\n"
 
332
                  " group by a.TskCod,a.CreEdt,a.TspActOprID,b.TraCod\n"
 
333
                  "having count(a.TspActOprID) > 0;\n"
 
334
                  "\n"
 
335
                  "CREATE OR REPLACE procedure spTuxGetAccData (oRet OUT  NUMBER)\n"
 
336
                  "AS\n"
 
337
                  "  vYear  CHAR(4);\n"
 
338
                  "BEGIN\n"
 
339
                  "    DECLARE\n"
 
340
                  "      oTrdStt NUMBER;\n"
 
341
                  "    BEGIN\n"
 
342
                  "      oTrdStt := 0;\n"
 
343
                  "    END;\n"
 
344
                  "    EXCEPTION\n"
 
345
                  "        WHEN VALUE_ERROR THEN\n"
 
346
                  "     oRet := 3;\n"
 
347
                  "END;"
 
348
#if 0
 
349
 
 
350
#endif
 
351
                  ;
 
352
 
 
353
    QApplication test(argc, argv);
 
354
    toMarkedText text(NULL);
 
355
    text.setText(res);
 
356
 
 
357
    {
 
358
        toSQLParse::editorTokenizer tokens(&text);
 
359
 
 
360
        std::list<toSQLParse::statement> stat = toSQLParse::parse(tokens);
 
361
 
 
362
        for (std::list<toSQLParse::statement>::iterator i = stat.begin();i != stat.end();i++)
 
363
        {
 
364
            printStatement(*i, 1);
 
365
        }
 
366
    }
 
367
 
 
368
    QString firstparse = toSQLParse::indent(res);
 
369
    QString secondparse = toSQLParse::indent(firstparse);
 
370
 
 
371
    printf("First\n\n%s\n", (const char *)firstparse);
 
372
 
 
373
    if (firstparse != secondparse)
 
374
    {
 
375
        printf("Reparse doesn't match\n");
 
376
        printf("Second\n\n%s\n", (const char *)secondparse);
 
377
    }
 
378
 
 
379
    return 0;
 
380
}
 
381
 
 
382
#endif
 
383
 
 
384
toSQLParse::statement::statement(type ntype, const QString &token, int cline)
 
385
        : Type(ntype), String(token), Line(cline)
 
386
{
 
387
    SubTokens = NULL;
 
388
}
 
389
 
 
390
std::list<toSQLParse::statement> &toSQLParse::statement::subTokens(void)
 
391
{
 
392
    if (!SubTokens)
 
393
        SubTokens = new std::list<statement>;
 
394
    return *SubTokens;
 
395
}
 
396
 
 
397
toSQLParse::statement::~statement()
 
398
{
 
399
    delete SubTokens;
 
400
}
 
401
 
 
402
toSQLParse::statement::statement(const statement &stat)
 
403
{
 
404
    Type = stat.Type;
 
405
    String = stat.String;
 
406
    Comment = stat.Comment;
 
407
    Line = stat.Line;
 
408
    if (stat.SubTokens)
 
409
    {
 
410
        SubTokens = new std::list<statement>;
 
411
        (*SubTokens) = (*stat.SubTokens);
 
412
    }
 
413
    else
 
414
        SubTokens = NULL;
 
415
}
 
416
 
 
417
const toSQLParse::statement &toSQLParse::statement::operator = (const statement &stat)
 
418
{
 
419
    Type = stat.Type;
 
420
    String = stat.String;
 
421
    Comment = stat.Comment;
 
422
    Line = stat.Line;
 
423
    delete SubTokens;
 
424
    if (stat.SubTokens)
 
425
    {
 
426
        SubTokens = new std::list<statement>;
 
427
        (*SubTokens) = (*stat.SubTokens);
 
428
    }
 
429
    else
 
430
        SubTokens = NULL;
 
431
    return *this;
 
432
}
 
433
 
 
434
bool toSQLParse::statement::operator == (const statement &stat) const
 
435
{
 
436
    if (Type != stat.Type ||
 
437
            Comment != stat.Comment ||
 
438
            String != stat.String)
 
439
        return false;
 
440
    if (SubTokens)
 
441
    {
 
442
        if (!stat.SubTokens && SubTokens->begin() != SubTokens->end())
 
443
            return false;
 
444
        if ((*SubTokens) != (*stat.SubTokens))
 
445
            return false;
 
446
    }
 
447
    else if (stat.SubTokens && stat.SubTokens->begin() != stat.SubTokens->end())
 
448
        return false;
 
449
    return true;
 
450
}
 
451
 
 
452
static const char *Operators[] =
 
453
    {":=",
 
454
     "=>",
 
455
     "||",
 
456
     "**",
 
457
     "<<",
 
458
     ">>",
 
459
     "..",
 
460
     "<>",
 
461
     "!=",
 
462
     "~=",
 
463
     "^=",
 
464
     "<=",
 
465
     ">=",
 
466
     NULL
 
467
    };
 
468
 
 
469
QString toSQLParse::stringTokenizer::getToken(bool forward, bool comments)
 
470
{
 
471
    QChar c;
 
472
    QChar nc;
 
473
    QChar endString;
 
474
 
 
475
    enum {
 
476
        space,
 
477
        any,
 
478
        identifier,
 
479
        string,
 
480
        comment,
 
481
        label,
 
482
        bindOpen,
 
483
        bindClose
 
484
    } state = space;
 
485
 
 
486
    QString token;
 
487
 
 
488
    int inc = forward ? 1 : -1;
 
489
 
 
490
    while ((forward && Offset < int(String.length())) || (!forward && Offset >= 1))
 
491
    {
 
492
        if (!forward)
 
493
            Offset--;
 
494
        c = String[Offset];
 
495
        if (c == '\n')
 
496
            Line++;
 
497
        if ((forward && Offset < int(String.length() - 1)) || (!forward && Offset > 0))
 
498
            nc = String[Offset + inc];
 
499
        else
 
500
            nc = '\n';
 
501
        if (state == space)
 
502
        {
 
503
            if (forward && c == '-' && nc == '-')
 
504
            {
 
505
                int spos = Offset;
 
506
                if (forward)
 
507
                    for (Offset++;Offset < int(String.length()) && String[Offset] != '\n';Offset++)
 
508
                        ;
 
509
                if (comments)
 
510
                    return String.mid(spos, Offset - spos);
 
511
                continue;
 
512
            }
 
513
            if (c == '/' && nc == '*')
 
514
                state = comment;
 
515
            else if ((forward && c == '<' && nc == '<') ||
 
516
                     (!forward && c == '>' && nc == '>'))
 
517
                state = label;
 
518
            else if (!c.isSpace())
 
519
                state = any;
 
520
        }
 
521
 
 
522
        if (forward)
 
523
            Offset++;
 
524
 
 
525
        if (state != space)
 
526
        {
 
527
            if (forward)
 
528
                token += c;
 
529
            else
 
530
                token.prepend(c);
 
531
            switch (state)
 
532
            {
 
533
            case comment:
 
534
                if (c == '*' && nc == '/')
 
535
                {
 
536
                    if (forward)
 
537
                        token += nc;
 
538
                    else
 
539
                        token.prepend(nc);
 
540
                    Offset += inc;
 
541
                    if (comments)
 
542
                        return token;
 
543
                    else
 
544
                    {
 
545
                        state = space;
 
546
                        token = QString::null;
 
547
                    }
 
548
                }
 
549
                break;
 
550
            case label:
 
551
                if ((forward && c == '>' && nc == '>') ||
 
552
                        (!forward && c == '<' && nc == '<'))
 
553
                {
 
554
                    if (forward)
 
555
                        token += nc;
 
556
                    else
 
557
                        token.prepend(nc);
 
558
                    Offset += inc;
 
559
                    return token;
 
560
                }
 
561
                break;
 
562
            case space:
 
563
                break;
 
564
            case bindOpen:
 
565
                if (!toIsIdent(nc))
 
566
                {
 
567
                    if (nc == '<')
 
568
                        state = bindClose;
 
569
                    else
 
570
                        return token;
 
571
                }
 
572
                break;
 
573
            case bindClose:
 
574
                if (c == '>')
 
575
                    return token;
 
576
                break;
 
577
            case any:
 
578
                if (c == ':' && toIsIdent(nc))
 
579
                {
 
580
                    state = bindOpen;
 
581
                }
 
582
                else if (toIsIdent(c))
 
583
                {
 
584
                    if (!toIsIdent(nc))
 
585
                        return token;
 
586
                    state = identifier;
 
587
                }
 
588
                else if (c == '\'' || c == analyzer().quoteCharacter())
 
589
                {
 
590
                    endString = c;
 
591
                    state = string;
 
592
                }
 
593
                else
 
594
                {
 
595
                    for (int i = 0;Operators[i];i++)
 
596
                    {
 
597
                        if ((forward && c == Operators[i][0] && nc == Operators[i][1]) ||
 
598
                                (!forward && nc == Operators[i][0] && c == Operators[i][1]))
 
599
                        {
 
600
                            if (forward)
 
601
                                token += nc;
 
602
                            else
 
603
                                token.prepend(nc);
 
604
                            Offset += inc;
 
605
                            break;
 
606
                        }
 
607
                    }
 
608
                    return token;
 
609
                }
 
610
                break;
 
611
            case identifier:
 
612
                if (!toIsIdent(nc))
 
613
                    return token;
 
614
                break;
 
615
            case string:
 
616
                if (c == endString)
 
617
                {
 
618
                    if (nc == endString)
 
619
                    {
 
620
                        if (forward)
 
621
                        {
 
622
                            token += nc;
 
623
                            Offset++;
 
624
                        }
 
625
                        else
 
626
                        {
 
627
                            token.prepend(nc);
 
628
                            Offset--;
 
629
                        }
 
630
                    }
 
631
                    else
 
632
                        return token;
 
633
                }
 
634
                break;
 
635
            }
 
636
        }
 
637
    }
 
638
    return token;
 
639
}
 
640
 
 
641
QString toSQLParse::stringTokenizer::remaining(bool eol)
 
642
{
 
643
    QString ret;
 
644
    if (eol)
 
645
    {
 
646
        int pos = String.find('\n', Offset);
 
647
        if (pos < 0)
 
648
            pos = Offset;
 
649
        ret = String.mid(Offset, pos - Offset);
 
650
        Offset = pos;
 
651
    }
 
652
    else
 
653
    {
 
654
        ret = String.mid(Offset);
 
655
        Offset = String.length();
 
656
    }
 
657
    return ret;
 
658
}
 
659
 
 
660
toSQLParse::editorTokenizer::editorTokenizer(toMarkedText *editor, int offset, int line)
 
661
        : tokenizer(offset, line)
 
662
{
 
663
    Editor = editor;
 
664
    toHighlightedText *text = dynamic_cast<toHighlightedText *>(editor);
 
665
    if (text)
 
666
        setAnalyzer(text->analyzer());
 
667
}
 
668
 
 
669
QString toSQLParse::editorTokenizer::getToken(bool forward, bool comments)
 
670
{
 
671
    bool first = true;
 
672
    while (Line < int(Editor->lines()) && Line >= 0)
 
673
    {
 
674
        QString line = Editor->text(Line);
 
675
        if (!first)
 
676
        {
 
677
            if (forward)
 
678
                Offset = 0;
 
679
            else
 
680
                Offset = line.length();
 
681
        }
 
682
        stringTokenizer token(line, analyzer(), Offset, forward);
 
683
        QString ret = token.getToken(forward, true);
 
684
        Offset = token.offset();
 
685
 
 
686
        if (!ret.isNull())
 
687
        {
 
688
            if (forward)
 
689
            {
 
690
                QString end;
 
691
                if (ret.startsWith(("/*")) &&
 
692
                        (ret.at(ret.length() - 2) != '*' ||
 
693
                         ret.at(ret.length() - 1) != '/'))
 
694
                {
 
695
                    end = ("*/");
 
696
                }
 
697
                else if (ret.startsWith("'") && ((ret.contains("'") % 2) != 0 || ret.at(ret.length() - 1) != '\''))
 
698
                {
 
699
                    end = ("'");
 
700
                }
 
701
                else if (ret.startsWith(analyzer().quoteCharacter()) &&
 
702
                         ((ret.contains(analyzer().quoteCharacter()) % 2) != 0 || ret.at(ret.length() - 1) != analyzer().quoteCharacter()))
 
703
                {
 
704
                    end = analyzer().quoteCharacter();
 
705
                }
 
706
                if (!end.isNull())
 
707
                {
 
708
                    for (Line++;
 
709
                            Line < int(Editor->lines()) && (Offset = Editor->text(Line).find(end)) < 0;
 
710
                            Line++)
 
711
                        ret += ("\n") + Editor->text(Line);
 
712
                    if (Line < int(Editor->lines()))
 
713
                    {
 
714
                        ret += ("\n") + Editor->text(Line).mid(0, Offset + end.length());
 
715
                        Offset += end.length();
 
716
                    }
 
717
                }
 
718
            }
 
719
            else
 
720
            {
 
721
                QString end;
 
722
                if (ret.length() >= 2 &&
 
723
                        ret.at(ret.length() - 2) == '*' &&
 
724
                        ret.at(ret.length() - 1) == '/' &&
 
725
                        !ret.startsWith(("/*")))
 
726
                {
 
727
                    end = ("/*");
 
728
                }
 
729
                else if ((ret.length() >= 1 && ret.at(ret.length() - 1) == '\'') &&
 
730
                         (ret.length() < 2 || ret[0] != '\''))
 
731
                {
 
732
                    end = ("\'");
 
733
                }
 
734
                else if ((ret.length() >= 1 && ret.at(ret.length() - 1) == analyzer().quoteCharacter()) &&
 
735
                         (ret.length() < 2 || ret.at(0) != analyzer().quoteCharacter()))
 
736
                {
 
737
                    end = analyzer().quoteCharacter();
 
738
                }
 
739
                if (!end.isNull())
 
740
                {
 
741
                    for (Line--;
 
742
                            Line >= 0 && (Offset = Editor->text(Line).findRev(end)) < 0;
 
743
                            Line--)
 
744
                        ret.prepend(Editor->text(Line) + ("\n"));
 
745
                    if (Line >= 0)
 
746
                    {
 
747
                        QString str = Editor->text(Line);
 
748
                        ret.prepend(str.mid(Offset, str.length() - Offset) + ("\n"));
 
749
                    }
 
750
                }
 
751
            }
 
752
            if (comments || (!ret.startsWith(("/*")) && !ret.startsWith(("--")) && !ret.startsWith("//")))
 
753
                return ret;
 
754
            else
 
755
            {
 
756
                first = true;
 
757
                continue;
 
758
            }
 
759
        }
 
760
        Line += (forward ? 1 : -1);
 
761
        first = false;
 
762
    }
 
763
    return QString::null;
 
764
}
 
765
 
 
766
QString toSQLParse::editorTokenizer::remaining(bool eol)
 
767
{
 
768
    if (Line >= Editor->lines())
 
769
        return QString::null;
 
770
    if (!eol)
 
771
    {
 
772
        QStringList rows;
 
773
        rows << Editor->text(Line).mid(Offset);
 
774
        for (int i = Line;i < Editor->lines();i++)
 
775
            rows << Editor->text(i);
 
776
        Line = Editor->lines();
 
777
        Offset = 0;
 
778
        return rows.join(("\n"));
 
779
    }
 
780
    else
 
781
    {
 
782
        QString line = Editor->text(Line);
 
783
        QString ret = line.mid(offset());
 
784
        Offset = line.length();
 
785
        return ret;
 
786
    }
 
787
}
 
788
 
 
789
toSQLParse::statement toSQLParse::parseStatement(tokenizer &tokens, bool declare, bool lst)
 
790
{
 
791
    statement ret(statement::Statement);
 
792
 
 
793
    toSyntaxAnalyzer &syntax = tokens.analyzer();
 
794
 
 
795
    QString first;
 
796
    QString realfirst;
 
797
    bool nokey = false;
 
798
    bool block = false;
 
799
    for (QString token = tokens.getToken(true, true);
 
800
            !token.isNull();
 
801
            token = tokens.getToken(true, true))
 
802
    {
 
803
        QString upp = token.upper();
 
804
#ifdef TOPARSE_DEBUG
 
805
 
 
806
        printf("%s (%d)\n", (const char*)token, tokens.line());
 
807
#endif
 
808
 
 
809
        if (first.isNull() && !token.startsWith(("/*")) && !token.startsWith("--") && !token.startsWith("//"))
 
810
            realfirst = first = upp;
 
811
 
 
812
        if (upp == ("PROCEDURE") ||
 
813
                upp == ("FUNCTION") ||
 
814
                upp == ("PACKAGE"))
 
815
            block = true;
 
816
 
 
817
        if (upp == ("SELF"))
 
818
            block = false;
 
819
 
 
820
        if (first != ("END") && ((first == ("IF") && upp == ("THEN")) ||
 
821
                                 upp == ("LOOP") ||
 
822
                                 upp == ("DO") ||
 
823
                                 (syntax.declareBlock() && upp == ("DECLARE")) ||
 
824
                                 (block && upp == ("AS")) ||
 
825
                                 (block && upp == ("IS")) ||
 
826
                                 ((!declare || block) && upp == ("BEGIN"))))
 
827
        {
 
828
            block = false;
 
829
            statement blk(statement::Block);
 
830
            ret.subTokens().insert(ret.subTokens().end(), statement(statement::Keyword, token, tokens.line()));
 
831
            blk.subTokens().insert(blk.subTokens().end(), ret);
 
832
            statement cur(statement::Statement);
 
833
            bool dcl = (upp == ("DECLARE") || upp == ("IS") || upp == ("AS"));
 
834
            do
 
835
            {
 
836
                cur = parseStatement(tokens, dcl, false);
 
837
                if (cur.Type == statement::List)
 
838
                    toStatusMessage(qApp->translate("toSQLparse", "Unbalanced parenthesis (Too many ')')"));
 
839
                blk.subTokens().insert(blk.subTokens().end(), cur);
 
840
                if (cur.subTokens().begin() != cur.subTokens().end() &&
 
841
                        (*(cur.subTokens().begin())).String.upper() == ("BEGIN"))
 
842
                    dcl = false;
 
843
            }
 
844
            while (cur.subTokens().begin() != cur.subTokens().end() &&
 
845
                    (*cur.subTokens().begin()).String.upper() != ("END"));
 
846
            return blk;
 
847
        }
 
848
        else if (((first == "IF" && upp == "THEN") ||
 
849
                  (first == "WHEN" && upp == "THEN") ||
 
850
                  (first == "ELSIF" && upp == "THEN") ||
 
851
                  upp == ("BEGIN") ||
 
852
                  upp == ("EXCEPTION") ||
 
853
                  first == ("ELSE")) && !lst)
 
854
        {
 
855
            ret.subTokens().insert(ret.subTokens().end(), statement(statement::Keyword, token, tokens.line()));
 
856
            return ret;
 
857
        }
 
858
        else if (first == ("ASSIGN") ||
 
859
                 first == ("SET") ||
 
860
                 first == ("PROMPT") ||
 
861
                 first == ("COLUMN") ||
 
862
                 first == ("SPOOL") ||
 
863
                 first == ("STORE") ||
 
864
                 first == ("REMARK") ||
 
865
                 first == ("REM"))
 
866
        {
 
867
            ret.subTokens().insert(ret.subTokens().end(), statement(statement::Keyword, token, tokens.line()));
 
868
            int line = tokens.line();
 
869
            int offset = tokens.offset();
 
870
            for (QString tmp = tokens.getToken(true, true);line == tokens.line();tmp = tokens.getToken(true, true))
 
871
                ret.subTokens().insert(ret.subTokens().end(), statement(statement::Token, tmp, line));
 
872
            tokens.setLine(line);
 
873
            tokens.setOffset(offset);
 
874
            tokens.remaining(true);
 
875
            return ret;
 
876
        }
 
877
        else if (upp == (",") ||
 
878
                 (syntax.reservedWord(upp) &&
 
879
                  upp != ("NOT") &&
 
880
                  upp != ("IS") &&
 
881
                  upp != ("LIKE") &&
 
882
                  upp != ("IN") &&
 
883
                  upp != ("ELSE") &&
 
884
                  upp != ("ELSIF") &&
 
885
                  upp != ("END") &&
 
886
                  upp != ("BETWEEN") &&
 
887
                  upp != ("ASC") &&
 
888
                  upp != ("DESC") &&
 
889
                  upp != ("NULL")) && !nokey)
 
890
        {
 
891
            ret.subTokens().insert(ret.subTokens().end(), statement(statement::Keyword, token, tokens.line()));
 
892
            nokey = false;
 
893
        }
 
894
        else if (upp == ("("))
 
895
        {
 
896
            ret.subTokens().insert(ret.subTokens().end(), statement(statement::Token, token, tokens.line()));
 
897
            statement lst = parseStatement(tokens, false, true);
 
898
            statement t = toPop(lst.subTokens());
 
899
            if (lst.Type != statement::List)
 
900
                toStatusMessage(qApp->translate("toSQLparse", "Unbalanced parenthesis (Too many '(')"));
 
901
            nokey = false;
 
902
            if (first == ("CREATE") && !block)
 
903
            {
 
904
                statement end = parseStatement(tokens, false, true);
 
905
                statement blk(statement::Block);
 
906
                blk.subTokens().insert(blk.subTokens().end(), ret);
 
907
                blk.subTokens().insert(blk.subTokens().end(), lst);
 
908
                end.subTokens().insert(end.subTokens().begin(), t);
 
909
                blk.subTokens().insert(blk.subTokens().end(), end);
 
910
                return blk;
 
911
            }
 
912
            else
 
913
            {
 
914
                ret.subTokens().insert(ret.subTokens().end(), lst);
 
915
                ret.subTokens().insert(ret.subTokens().end(), t);
 
916
            }
 
917
        }
 
918
        else if (upp == (")"))
 
919
        {
 
920
            ret.Type = statement::List;
 
921
            ret.subTokens().insert(ret.subTokens().end(), statement(statement::Token, token, tokens.line()));
 
922
            return ret;
 
923
        }
 
924
        else if (upp == (";"))
 
925
        {
 
926
            ret.subTokens().insert(ret.subTokens().end(), statement(statement::Token, token, tokens.line()));
 
927
            return ret;
 
928
        }
 
929
        else if (upp.startsWith(("/*+")) || upp.startsWith(("--+")))
 
930
        {
 
931
            QString com = token;
 
932
            if (com.startsWith(("--+")))
 
933
                com = ("/*+ ") + com.mid(3) + (" */");
 
934
            ret.subTokens().insert(ret.subTokens().end(), statement(statement::Token,
 
935
                                   com.simplifyWhiteSpace(), tokens.line()));
 
936
        }
 
937
        else if (upp.startsWith(("/*")) || upp.startsWith(("--")) || upp.startsWith("//"))
 
938
        {
 
939
            if ( ret.subTokens().empty() )
 
940
            {
 
941
                if (ret.Comment.isNull())
 
942
                    ret.Comment = token;
 
943
                else
 
944
                    ret.Comment += ("\n") + token;
 
945
            }
 
946
            else
 
947
            {
 
948
                QString &com = (*ret.subTokens().rbegin()).Comment;
 
949
                if (com.isEmpty())
 
950
                    com = token;
 
951
                else
 
952
                    com += ("\n") + token;
 
953
            }
 
954
        }
 
955
        else
 
956
        {
 
957
            ret.subTokens().insert(ret.subTokens().end(), statement(statement::Token, token, tokens.line()));
 
958
            nokey = (token == ("."));
 
959
        }
 
960
        if (upp == ("AS") || upp == ("IS"))
 
961
            first = upp;
 
962
        else if (first == ("IS") && upp == ("NULL"))
 
963
            first = realfirst;
 
964
    }
 
965
    return ret;
 
966
}
 
967
 
 
968
std::list<toSQLParse::statement> toSQLParse::parse(tokenizer &tokens)
 
969
{
 
970
    std::list<toSQLParse::statement> ret;
 
971
    statement cur(statement::Statement);
 
972
    for (cur = parseStatement(tokens, false, false);
 
973
            cur.subTokens().begin() != cur.subTokens().end();
 
974
            cur = parseStatement(tokens, false, false))
 
975
    {
 
976
        if (cur.Type == statement::List)
 
977
            toStatusMessage(qApp->translate("toSQLparse", "Unbalanced parenthesis (Too many ')')"));
 
978
        ret.insert(ret.end(), cur);
 
979
    }
 
980
    QString str = tokens.remaining(false);
 
981
    if (!str.isEmpty())
 
982
        ret.insert(ret.end(), statement(statement::Raw,
 
983
                                        str, tokens.line()));
 
984
    return ret;
 
985
}
 
986
 
 
987
toSQLParse::statement toSQLParse::parseStatement(tokenizer &tokens)
 
988
{
 
989
    statement cur(statement::Statement);
 
990
    cur = parseStatement(tokens, false, false);
 
991
    if (cur.Type == statement::List)
 
992
        toStatusMessage(qApp->translate("toSQLparse", "Unbalanced parenthesis (Too many ')')"));
 
993
    return cur;
 
994
}
 
995
 
 
996
int toSQLParse::countIndent(const QString &txt, int &chars)
 
997
{
 
998
    int level = 0;
 
999
    while (txt[chars].isSpace() && chars < int(txt.length()))
 
1000
    {
 
1001
        char c = txt[chars].latin1();
 
1002
        if (c == '\n')
 
1003
            level = 0;
 
1004
        else if (c == ' ')
 
1005
            level++;
 
1006
        else if (c == '\t')
 
1007
            level = (level / toMarkedText::defaultTabWidth() + 1) * toMarkedText::defaultTabWidth();
 
1008
        chars++;
 
1009
    }
 
1010
    return level;
 
1011
}
 
1012
 
 
1013
toSQLParse::settings toSQLParse::Settings = {true,
 
1014
        false,
 
1015
        false,
 
1016
        false,
 
1017
        true,
 
1018
        true,
 
1019
        true,
 
1020
        4,
 
1021
        60};
 
1022
 
 
1023
QString toSQLParse::indentString(int level)
 
1024
{
 
1025
    QString ret;
 
1026
    if (Settings.ExpandSpaces)
 
1027
    {
 
1028
        for (int i = 0;i < level / 8;i++)
 
1029
            ret += ("\t");
 
1030
        for (int j = 0;j < level % 8;j++)
 
1031
            ret += (" ");
 
1032
    }
 
1033
    else
 
1034
        for (int j = 0;j < level;j++)
 
1035
            ret += (" ");
 
1036
    return ret;
 
1037
}
 
1038
 
 
1039
static int CurrentColumn(const QString &txt)
 
1040
{
 
1041
    int pos = txt.findRev(("\n"));
 
1042
    if (pos < 0)
 
1043
        pos = 0;
 
1044
    else
 
1045
        pos++;
 
1046
 
 
1047
    int level = 0;
 
1048
    while (pos < int(txt.length()))
 
1049
    {
 
1050
        char c = txt[pos].latin1();
 
1051
        if (c == '\n')
 
1052
            level = 0;
 
1053
        else if (c == '\t')
 
1054
            level = (level / toMarkedText::defaultTabWidth() + 1) * toMarkedText::defaultTabWidth();
 
1055
        else
 
1056
            level++;
 
1057
        pos++;
 
1058
    }
 
1059
    return level;
 
1060
 
 
1061
}
 
1062
 
 
1063
static QString IndentComment(int level, int current, const QString &comment, bool endNl)
 
1064
{
 
1065
    bool nl = true;
 
1066
    QString ret;
 
1067
    if (comment.length())
 
1068
    {
 
1069
        if (level <= current && (level || current))
 
1070
        {
 
1071
            ret += ("\n");
 
1072
            current = 0;
 
1073
        }
 
1074
        for (unsigned int i = 0;i < comment.length();i++)
 
1075
        {
 
1076
            if (!nl || !comment.at(i).isSpace())
 
1077
            {
 
1078
                if (nl)
 
1079
                {
 
1080
                    if (current == 0)
 
1081
                        ret += toSQLParse::indentString(level);
 
1082
                    else
 
1083
                    {
 
1084
                        while (current < level)
 
1085
                        {
 
1086
                            ret += (" ");
 
1087
                            current++;
 
1088
                        }
 
1089
                    }
 
1090
                    if (comment.at(i) == ("*"))
 
1091
                    {
 
1092
                        ret += (" ");
 
1093
                        current++;
 
1094
                    }
 
1095
                    nl = false;
 
1096
                }
 
1097
                ret += comment.at(i);
 
1098
                if (comment.at(i) == '\n')
 
1099
                {
 
1100
                    current = 0;
 
1101
                    nl = true;
 
1102
                }
 
1103
                else
 
1104
                    nl = false;
 
1105
            }
 
1106
        }
 
1107
        if (!nl)
 
1108
            ret += ("\n");
 
1109
    }
 
1110
    else if (endNl)
 
1111
    {
 
1112
        ret = ("\n");
 
1113
    }
 
1114
    return ret;
 
1115
}
 
1116
 
 
1117
static QString AddComment(const QString &old, const QString &comment)
 
1118
{
 
1119
    QString ret = old;
 
1120
    if (!ret.isEmpty() && !comment.isEmpty())
 
1121
        ret += ("\n");
 
1122
    ret += comment;
 
1123
    return ret;
 
1124
}
 
1125
 
 
1126
QString toSQLParse::indentStatement(statement &stat, int level)
 
1127
{
 
1128
    return indentStatement(stat, level, toSyntaxAnalyzer::defaultAnalyzer());
 
1129
}
 
1130
 
 
1131
QString toSQLParse::indentStatement(statement &stat, toConnection &conn, int level)
 
1132
{
 
1133
    return indentStatement(stat, level, conn.analyzer());
 
1134
}
 
1135
 
 
1136
QString toSQLParse::indentStatement(statement &stat, int level, toSyntaxAnalyzer &syntax)
 
1137
{
 
1138
    QString ret;
 
1139
 
 
1140
    switch (stat.Type)
 
1141
    {
 
1142
    default:
 
1143
        throw qApp->translate("toSQLparse", "Internal error in toSQLParse, should never get here");
 
1144
    case statement::Block:
 
1145
        {
 
1146
            ret = IndentComment(level, 0, stat.Comment, false);
 
1147
            int exc = 0;
 
1148
            for (std::list<toSQLParse::statement>::iterator i = stat.subTokens().begin();
 
1149
                    i != stat.subTokens().end();
 
1150
                    i++)
 
1151
            {
 
1152
                int add
 
1153
                    = 0;
 
1154
                std::list<toSQLParse::statement>::iterator j = i;
 
1155
                j++;
 
1156
                if (i != stat.subTokens().begin() &&
 
1157
                        j != stat.subTokens().end())
 
1158
                    add
 
1159
                        = Settings.IndentLevel;
 
1160
                else
 
1161
                    exc = 0;
 
1162
 
 
1163
                QString t;
 
1164
                if ((*i).subTokens().begin() != (*i).subTokens().
 
1165
                        end())
 
1166
                    t = (*(*i).subTokens().begin()).String.upper();
 
1167
                if (t == ("BEGIN") || t == ("WHEN") || t == ("ELSE") || t == ("ELSIF"))
 
1168
                    add
 
1169
                        = 0;
 
1170
                if ((*i).Type == statement::List)
 
1171
                    ret += indentString(level + add
 
1172
                                            + exc);
 
1173
                ret += indentStatement(*i, level + add
 
1174
                                           + exc, syntax);
 
1175
                if ((*i).Type == statement::List)
 
1176
                {
 
1177
                    int i;
 
1178
                    for (i = ret.length() - 1;i >= 0 && ret[i].isSpace();i--)
 
1179
                        ;
 
1180
                    ret = ret.mid(0, std::max(i + 1, 0));
 
1181
                    ret += ("\n");
 
1182
                    ret += indentString(level + exc);
 
1183
                }
 
1184
                if (t == ("EXCEPTION"))
 
1185
                    exc = Settings.IndentLevel * 2;
 
1186
            }
 
1187
            if (Settings.EndBlockNewline && level != 0)
 
1188
                ret += ("\n");
 
1189
        }
 
1190
        break;
 
1191
    case statement::List:
 
1192
    case statement::Statement:
 
1193
        int maxlev = 0;
 
1194
        int maxlevorig = 0;
 
1195
        bool useMaxLev = false;
 
1196
        bool any = true;
 
1197
        int current;
 
1198
        bool first;
 
1199
        bool noKeyBreak = false;
 
1200
        bool lineList = false;
 
1201
        QString comment;
 
1202
        if (stat.Type == statement::Statement)
 
1203
        {
 
1204
            ret = IndentComment(level, 0, stat.Comment, false);
 
1205
            useMaxLev = true;
 
1206
            first = true;
 
1207
            current = 0;
 
1208
        }
 
1209
        else
 
1210
        {
 
1211
            for (std::list<toSQLParse::statement>::iterator i = stat.subTokens().begin();
 
1212
                    i != stat.subTokens().end();)
 
1213
            {
 
1214
                if ((*i).Type != statement::Keyword)
 
1215
                    noKeyBreak = true;
 
1216
                else
 
1217
                    useMaxLev = true;
 
1218
                break;
 
1219
            }
 
1220
            current = level;
 
1221
            first = true;
 
1222
        }
 
1223
        if (useMaxLev)
 
1224
        {
 
1225
            int count = 0;
 
1226
            for (std::list<toSQLParse::statement>::iterator i = stat.subTokens().begin();
 
1227
                    i != stat.subTokens().end();
 
1228
                    i++)
 
1229
            {
 
1230
                if (any)
 
1231
                {
 
1232
                    QString upp = (*i).String.upper();
 
1233
                    if ((*i).Type == statement::Keyword &&
 
1234
                            upp != ("LOOP") &&
 
1235
                            upp != ("DO") &&
 
1236
                            upp != ("THEN") &&
 
1237
                            upp != ("AS") &&
 
1238
                            upp != ("IS"))
 
1239
                    {
 
1240
                        if (int((*i).String.length()) + 1 > maxlev)
 
1241
                            maxlev = (*i).String.length() + 1;
 
1242
                        count++;
 
1243
                        any = false;
 
1244
                    }
 
1245
                    else if (i == stat.subTokens().begin())
 
1246
                    {
 
1247
                        noKeyBreak = true;
 
1248
                        break;
 
1249
                    }
 
1250
                }
 
1251
                else if ((*i).Type == statement::Token)
 
1252
                    any = true;
 
1253
                if ((*i).Type == statement::List)
 
1254
                    count++;
 
1255
            }
 
1256
            if (count <= 1 && maxlev > 0)
 
1257
                maxlev--;
 
1258
            maxlevorig = maxlev;
 
1259
            any = true;
 
1260
        }
 
1261
 
 
1262
        for (std::list<toSQLParse::statement>::iterator i = stat.subTokens().begin();
 
1263
                i != stat.subTokens().end();
 
1264
                i++)
 
1265
        {
 
1266
            comment = AddComment(comment, (*i).Comment);
 
1267
            QString upp = (*i).String.upper();
 
1268
#ifdef TOPARSE_DEBUG
 
1269
 
 
1270
            printf("%s\n", (const char*)(*i).String.latin1());
 
1271
#endif
 
1272
 
 
1273
            if ((*i).Type == statement::List)
 
1274
            {
 
1275
                if (Settings.OperatorSpace)
 
1276
                {
 
1277
                    ret += (" ");
 
1278
                    current++;
 
1279
                }
 
1280
                QString t = indentStatement(*i, current, syntax);
 
1281
                if (t.find(("\n")) >= 0)
 
1282
                    current = CurrentColumn(t);
 
1283
                else
 
1284
                    current += CurrentColumn(t);
 
1285
                ret += t;
 
1286
                any = true;
 
1287
            }
 
1288
            else if ((*i).String == (","))
 
1289
            {
 
1290
                if (Settings.CommaBefore)
 
1291
                {
 
1292
                    ret += IndentComment(Settings.CommentColumn, current, comment, true);
 
1293
                    comment = QString::null;
 
1294
                    ret += indentString(level + maxlev - (Settings.OperatorSpace ? 2 : 1));
 
1295
                    ret += (",");
 
1296
                }
 
1297
                else
 
1298
                {
 
1299
                    ret += (",");
 
1300
                    ret += IndentComment(Settings.CommentColumn, current + 1, comment, true);
 
1301
                    comment = QString::null;
 
1302
                    ret += indentString(level + maxlev);
 
1303
                }
 
1304
                current = level + maxlev;
 
1305
                any = false;
 
1306
                lineList = true;
 
1307
            }
 
1308
            else if ((*i).Type == statement::Keyword && (upp == ("LOOP") ||
 
1309
                     upp == ("DO") ||
 
1310
                     upp == ("THEN") ||
 
1311
                     upp == ("AS") ||
 
1312
                     upp == ("IS")))
 
1313
            {
 
1314
                if (!Settings.BlockOpenLine)
 
1315
                {
 
1316
                    if (ret.length() > 0)
 
1317
                    {
 
1318
                        if (toIsIdent(ret.at(ret.length() - 1)) ||
 
1319
                                ret.at(ret.length() - 1) == syntax.quoteCharacter() ||
 
1320
                                ret.at(ret.length() - 1) == '\'' ||
 
1321
                                Settings.OperatorSpace)
 
1322
                        {
 
1323
                            ret += (" ");
 
1324
                            current++;
 
1325
                        }
 
1326
                    }
 
1327
                    ret += Settings.KeywordUpper ? (*i).String.upper() : (*i).String;
 
1328
                    current += (*i).String.length();
 
1329
                }
 
1330
                else
 
1331
                {
 
1332
                    ret += IndentComment(Settings.CommentColumn, current, comment, true);
 
1333
                    comment = QString::null;
 
1334
                    ret += indentString(level);
 
1335
                    ret += Settings.KeywordUpper ? (*i).String.upper() : (*i).String;
 
1336
                    current = level + (*i).String.length();
 
1337
                }
 
1338
                any = false;
 
1339
            }
 
1340
            else if (any && (*i).Type == statement::Keyword && !noKeyBreak)
 
1341
            {
 
1342
                if (first)
 
1343
                    first = false;
 
1344
                else
 
1345
                {
 
1346
                    ret += IndentComment(Settings.CommentColumn, current, comment, true);
 
1347
                    current = 0;
 
1348
                    comment = QString::null;
 
1349
                }
 
1350
                if (current == 0)
 
1351
                {
 
1352
                    ret += indentString(level);
 
1353
                    current = level;
 
1354
                }
 
1355
                else
 
1356
                    while (current < level)
 
1357
                    {
 
1358
                        ret += (" ");
 
1359
                        current++;
 
1360
                    }
 
1361
                maxlev = maxlevorig;
 
1362
                QString word = Settings.KeywordUpper ? (*i).String.upper() : (*i).String;
 
1363
                if (ret.length())
 
1364
                {
 
1365
                    ret += QString("%1").arg(word,
 
1366
                                             Settings.RightSeparator ? maxlev - 1 : 1 - maxlev);
 
1367
                    current = level + std::max(int(word.length()), maxlev - 1);
 
1368
                }
 
1369
                else
 
1370
                {
 
1371
                    ret += word;
 
1372
                    current = level + word.length();
 
1373
                }
 
1374
                any = false;
 
1375
                lineList = false;
 
1376
            }
 
1377
            else
 
1378
            {
 
1379
                QString t = (*i).String;
 
1380
                bool add
 
1381
                    = false;
 
1382
                if ((*i).Type == statement::Keyword)
 
1383
                {
 
1384
                    if (!lineList &&
 
1385
                            !any &&
 
1386
                            (*i).Type == statement::Keyword &&
 
1387
                            !noKeyBreak &&
 
1388
                            upp == ("BY"))
 
1389
                        add
 
1390
                            = true;
 
1391
                }
 
1392
                else
 
1393
                {
 
1394
                    any = true;
 
1395
                }
 
1396
                if (syntax.reservedWord(upp) && Settings.KeywordUpper)
 
1397
                    t = upp;
 
1398
 
 
1399
                int extra;
 
1400
                if (first)
 
1401
                {
 
1402
                    first = false;
 
1403
                    any = false;
 
1404
                    extra = 0;
 
1405
                }
 
1406
                else
 
1407
                {
 
1408
                    if (ret.length() > 0 &&
 
1409
                            !ret.at(ret.length() - 1).isSpace() &&
 
1410
                            (Settings.OperatorSpace || ((toIsIdent(t[0]) ||
 
1411
                                                         t[0] == syntax.quoteCharacter() || t[0] == '\'') &&
 
1412
                                                        (toIsIdent(ret.at(ret.length() - 1)) ||
 
1413
                                                         ret.at(ret.length() - 1) == syntax.quoteCharacter() ||
 
1414
                                                         ret.at(ret.length() - 1) == '\'')
 
1415
                                                       )
 
1416
                            )
 
1417
                       )
 
1418
                    {
 
1419
                        if (t != (";") &&
 
1420
                                t != (".") &&
 
1421
                                ret.at(ret.length() - 1) != '.' &&
 
1422
                                current != 0)
 
1423
                        {
 
1424
                            current++;
 
1425
                            ret += (" ");
 
1426
                        }
 
1427
                    }
 
1428
                    else if (ret.length() > 2 && ret.at(ret.length() - 2) == '*' && ret.at(ret.length() - 1) == '/')
 
1429
                    {
 
1430
                        current++;
 
1431
                        ret += (" ");
 
1432
                    }
 
1433
                    extra = maxlev;
 
1434
                }
 
1435
                if (current < level + maxlev)
 
1436
                {
 
1437
                    if (current == 0)
 
1438
                        ret += indentString(level + maxlev);
 
1439
                    else
 
1440
                        while (current < level + maxlev)
 
1441
                        {
 
1442
                            ret += (" ");
 
1443
                            current++;
 
1444
                        }
 
1445
                    current = level + maxlev;
 
1446
                }
 
1447
                ret += t;
 
1448
                current += t.length();
 
1449
                if (t.startsWith(("<<")))
 
1450
                {
 
1451
                    ret += ("\n");
 
1452
                    current = 0;
 
1453
                }
 
1454
 
 
1455
                if (add
 
1456
                   )
 
1457
                    maxlev += t.length() + 1;
 
1458
            }
 
1459
        }
 
1460
        if (stat.Type == statement::Statement)
 
1461
        {
 
1462
            ret += IndentComment(Settings.CommentColumn, current, comment, true);
 
1463
            comment = QString::null;
 
1464
            if (Settings.EndBlockNewline &&
 
1465
                    level == 0 &&
 
1466
                    stat.subTokens().begin() != stat.subTokens().end() &&
 
1467
                    (*stat.subTokens().rbegin()).String == (";"))
 
1468
                ret += ("\n");
 
1469
        }
 
1470
        else if (!comment.isEmpty())
 
1471
        {
 
1472
            ret += IndentComment(Settings.CommentColumn, current, comment, true);
 
1473
            comment = QString::null;
 
1474
            ret += indentString(level - (Settings.OperatorSpace ? 2 : 1));
 
1475
        }
 
1476
        break;
 
1477
    }
 
1478
    return ret;
 
1479
}
 
1480
 
 
1481
QString toSQLParse::indent(const QString &str)
 
1482
{
 
1483
    return indent(str, toSyntaxAnalyzer::defaultAnalyzer());
 
1484
}
 
1485
 
 
1486
QString toSQLParse::indent(const QString &str, toConnection &conn)
 
1487
{
 
1488
    return indent(str, conn.analyzer());
 
1489
}
 
1490
 
 
1491
QString toSQLParse::indent(std::list<statement> &stat)
 
1492
{
 
1493
    return indent(stat, toSyntaxAnalyzer::defaultAnalyzer());
 
1494
}
 
1495
 
 
1496
QString toSQLParse::indent(std::list<statement> &stat, toConnection &conn)
 
1497
{
 
1498
    return indent(stat, conn.analyzer());
 
1499
}
 
1500
 
 
1501
QString toSQLParse::indent(const QString &str, toSyntaxAnalyzer &syntax)
 
1502
{
 
1503
    stringTokenizer tokenizer(str, syntax);
 
1504
    std::list<toSQLParse::statement> blk = parse(tokenizer);
 
1505
    int pos = 0;
 
1506
    int level = countIndent(str, pos);
 
1507
 
 
1508
    QString ret;
 
1509
    for (std::list<toSQLParse::statement>::iterator i = blk.begin();
 
1510
            i != blk.end();
 
1511
            i++)
 
1512
    {
 
1513
        ret += indentStatement(*i, level, syntax);
 
1514
    }
 
1515
    pos = ret.length();
 
1516
    while (pos > 0 && ret[pos - 1].isSpace())
 
1517
    {
 
1518
        pos--;
 
1519
    }
 
1520
    return ret.mid(0, pos) + ("\n");
 
1521
}
 
1522
 
 
1523
QString toSQLParse::indent(std::list<statement> &stat, toSyntaxAnalyzer &syntax)
 
1524
{
 
1525
    int pos = 0;
 
1526
 
 
1527
    QString ret;
 
1528
    for (std::list<toSQLParse::statement>::iterator i = stat.begin();
 
1529
            i != stat.end();
 
1530
            i++)
 
1531
    {
 
1532
        ret += indentStatement(*i, 0, syntax);
 
1533
    }
 
1534
    pos = ret.length();
 
1535
    while (pos > 0 && ret[pos - 1].isSpace())
 
1536
    {
 
1537
        pos--;
 
1538
    }
 
1539
    return ret.mid(0, pos) + ("\n");
 
1540
}
 
1541
 
 
1542
std::list<toSQLParse::statement> toSQLParse::parse(const QString &str, toConnection &conn)
 
1543
{
 
1544
    stringTokenizer tokenizer(str, conn.analyzer());
 
1545
    return parse(tokenizer);
 
1546
}
 
1547
 
 
1548
toSQLParse::statement toSQLParse::parseStatement(toSQLParse::tokenizer &tokens, toConnection &conn)
 
1549
{
 
1550
    tokens.setAnalyzer(conn.analyzer());
 
1551
    return parseStatement(tokens);
 
1552
}
 
1553
 
 
1554
toSyntaxAnalyzer &toSQLParse::tokenizer::analyzer()
 
1555
{
 
1556
    if (Analyzer)
 
1557
        return *Analyzer;
 
1558
    else
 
1559
        return toSyntaxAnalyzer::defaultAnalyzer();
 
1560
}