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

« back to all changes in this revision

Viewing changes to 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
 
}