⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xqyacc.y

📁 TxQuery is an SQL engine implemented in a TDataSet descendant component, that can parse SQL syntax,
💻 Y
📖 第 1 页 / 共 4 页
字号:
   with Column do
   begin
      ColumnExpr := ColText;
      if Assigned(Self.fAggregateList) then
      begin
        AggregateList.Free;    { free previous aggregate list}
        AggregateList := Self.fAggregateList; { assign the current list}
        Self.fAggregateList:= nil;    { define as nil the current }
      end;
      { mark also as a temporary column that will be deleted after result set is
        generated }
      IsTemporaryCol := True;
   end;
end;

procedure TxqParser.AddUpdateColumn(const ColumnName, ColumnExpr: String);
var
   UpdateItem: TUpdateItem;
begin
   UpdateItem := CurrentAnalizer.UpdateColumnList.Add;
   with UpdateItem do
   begin
      ColName := ColumnName;
      ColExpr := ColumnExpr;
   end;

end;

procedure TxqParser.AddWhereOptimize( const AFieldName, ARangeStart,
   ARangeEnd: String; ARelOperator: TRelationalOperator );
var
   WhereOptimize : TWhereOptimizeItem;
   N             : Integer;

   function DeleteStringDelim(const s: String): String;
   begin
      Result := s;
      if Length(Result) > 1 then
      begin
         if (Result[1] in xqbase.SQuote) and (Result[Length(Result)] in xqbase.SQuote) then
         Result:= Copy(Result, 2, Length(Result) - 2);
      end;
   end;

begin
   if Not (yyLexer as TxqLexer).IsWhereActive then Exit;
   N := CurrentAnalizer.WhereOptimizeList.Count - 1;
   if ((ARelOperator in [ropLE, ropLT]) or (ARelOperator in [ropGE, ropGT]) ) and (N > 0) then
   begin

      { I will check if the previous command was something like (CustNo >= 1000)
        and if so, and this is something like (CustNo <= 3000) then
       I will add to the previous optimize and will generate a ropBETWEEN range   }

      WhereOptimize:= CurrentAnalizer.WhereOptimizeList[N - 1];
      if ( ((ARelOperator in [ropLE, ropLT]) and (WhereOptimize.RelOperator in [ropGE, ropGT])) or
         ((ARelOperator in [ropGE, ropGT]) and (WhereOptimize.RelOperator in [ropLE, ropLT])) ) and
         (AnsiCompareText(WhereOptimize.FieldNames, AFieldName) = 0) then
      begin
         WhereOptimize.RangeEnd    := DeleteStringDelim( ARangeEnd );
         WhereOptimize.RelOperator := ropBETWEEN;
         Exit;
      end;
   end;

   WhereOptimize := CurrentAnalizer.WhereOptimizeList.Add;
   with WhereOptimize do
   begin
      FieldNames  := AFieldName;
      RangeStart  := DeleteStringDelim(ARangeStart);
      RangeEnd    := DeleteStringDelim(ARangeEnd);
      RelOperator := ARelOperator;
      CanOptimize := False;
   end;

end;

{ ALTER TABLE }
function TxqParser.CurrentAlterTable: TCreateTableItem;
begin
  if FNumTables > CurrentAnalizer.AlterTableList.Count - 1 then
     Result := CurrentAnalizer.AlterTableList.Add
  else
     Result:= CurrentAnalizer.AlterTableList[ FNumTables ];
end;

{ CREATE TABLE }
function TxqParser.CurrentCreateTable: TCreateTableItem;
begin
  if FNumTables > CurrentAnalizer.CreateTableList.Count - 1 then
     Result := CurrentAnalizer.CreateTableList.Add
  else
     Result:= CurrentAnalizer.CreateTableList[ FNumTables ];
end;

procedure TxqParser.SetTableName(const TableName: String);
begin
   CurrentCreateTable.TableName := TableName;
end;

procedure TxqParser.SetAlterTableName(const TableName: String);
begin
   CurrentAlterTable.TableName := TableName;
end;

procedure TxqParser.SetFieldParams(AFieldType, AScale, APrecision, ASize, ABlobType: Integer);
begin
  FFieldType := AFieldType;
  FScale     := AScale;
  FPrecision := APrecision;
  FSize      := ASize;
  FBlobType  := ABlobType;
end;

procedure TxqParser.AddAlterField(const FieldName: String; DropField: Boolean);
var
  I: Integer;
begin
  { check if field exists }
  with CurrentAlterTable do
     for I := 0 to FieldCount - 1 do
       if (AnsiCompareText(Fields[I].FieldName, FieldName) = 0)
         and (Fields[I].MustDrop=DropField) then
       begin
          yyerror(SDuplicateFieldName);
          yyabort;
          Exit;
       end;
  if (FFieldType = RW_BLOB) and not (FBlobType in [1..5]) then
  begin
    yyerror(SBlobFieldWrongType);
    yyabort;
  end;
  CurrentAlterTable.Fields.AddField(FieldName, FFieldType, FScale, FPrecision,
    FSize, FBlobType, DropField);
end;

procedure TxqParser.AddCreateField(const FieldName: String);
var
  I: Integer;
begin
  { check if field exists }
  with CurrentCreateTable do
     for I := 0 to FieldCount - 1 do
   if AnsiCompareText(Fields[I].FieldName, FieldName) = 0 then
   begin
      yyerror(SDuplicateFieldName);
      yyabort;
      Exit;
   end;
  if (FFieldType = RW_BLOB) and not (FBlobType in [1..5]) then
  begin
    yyerror(SBlobFieldWrongType);
    yyabort;
  end;
  CurrentCreateTable.Fields.AddField(FieldName,FFieldType, FScale, FPrecision,
    FSize, FBlobType, False);
end;

procedure TxqParser.AddPrimaryKeyField(const FieldName: String);
var
  I : Integer;
  Found : Boolean;
begin
  { check that the field exists in the list of field names }
  Found := False;
  with CurrentCreateTable do
     for I := 0 to FieldCount - 1 do
  if AnsiCompareText(Fields[I].FieldName, FieldName) = 0 then
  begin
     Found:= True;
     Break;
  end;
  if Not Found then
  begin
     yyerror(SFieldNameNotFound);
     yyabort;
  end;
  CurrentCreateTable.PrimaryKey.Add( FieldName );
end;

function TxqParser.CurrentInsertItem: TInsertItem;
begin
   if fNumInserts >= CurrentAnalizer.InsertList.Count then
      Result := CurrentAnalizer.InsertList.Add
   else
      Result := CurrentAnalizer.InsertList[fNumInserts];
end;

function TxqParser.CreateInListExpression( const Expr : String ) : String;
var
   I : Integer;
begin
   { This subroutine helps to change the syntax:
     custno IN (1000, 2000, 3000)
     to this :
     (custno = 1000) OR (custno = 2000) OR (custno = 3000) }
   Result := '';
   for i := 0 to fInPredicateList.Count - 1 do
   begin
      Result := Result + Format('(%s = %s)', [Expr, fInPredicateList[i]]);
      if i < fInPredicateList.Count - 1 then
        Result := Result + ' OR ';
   end;
   if fIsNotInList then
      Result := 'NOT ( ' + Result + ' )'
   else
      Result := '( ' + Result + ' )';
   fInPredicateList.Clear;
end;

%}

%start sql

%token _IDENTIFIER
%token _UINTEGER
%token _SINTEGER
%token _NUMERIC
%token _STRING

%token _COMA
%token _LPAREN
%token _RPAREN
%token _LSQUARE
%token _RSQUARE
%token _PERIOD
%token _SEMICOLON
%token _COLON

%left  RW_OR
%left  RW_AND
%left  _EQ _NEQ _GT _LT _GE _LE RW_BETWEEN RW_IN RW_LIKE
%left  _PLUS _SUB
%left  _DIV _MULT RW_MOD RW_IDIV RW_SHL RW_SHR
%right UMINUS       /* Negation--unary minus */
%right _EXP       /* exponentiation */
%left  RW_NOT
%token _ILLEGAL


/* other reserved words and tokens */
%token  _COMMENT
        _BLANK
        _TAB
        _NEWLINE
        RW_TRUE
        RW_FALSE
        RW_SELECT
        RW_DISTINCT
        RW_FROM
        RW_WHERE
        RW_ORDER
        RW_BY
        RW_ASC
        RW_DESC
        RW_AS
        RW_INNER
        RW_OUTER
        RW_FULL
        RW_JOIN
        RW_ON
        RW_GROUP
        RW_HAVING
        RW_ANY
        RW_ALL
        RW_SUM
        RW_AVG
        RW_COUNT
        RW_MIN
        RW_MAX
        RW_STDEV
        RW_LEFT
        RW_RIGHT
        RW_LEADING
        RW_TRAILING
        RW_BOTH
        RW_TRIM
        RW_EXTRACT
        RW_YEAR
        RW_MONTH
        RW_DAY
        RW_HOUR
        RW_MINUTE
        RW_SECOND
        RW_FOR
        RW_SUBSTRING
        RW_DELETE
        RW_UPDATE
        RW_INSERT
        RW_INTO
        RW_VALUES
        RW_SET
        RW_CAST
        RW_CHAR
        RW_INTEGER
        RW_BOOLEAN
        RW_DATE
        RW_TIME
        RW_DATETIME
        RW_FLOAT
        RW_ESCAPE
        RW_CREATE
        RW_TABLE
        RW_SMALLINT
        RW_MONEY
        RW_AUTOINC
        RW_PRIMARY
        RW_KEY
        RW_BLOB
        RW_INDEX
        RW_UNIQUE
        RW_DROP
        RW_TRANSFORM
        RW_PIVOT
        RW_UNION
        RW_WITH
        RW_IS
        RW_NULL
        RW_ALTER
        RW_COLUMN
        RW_ADD
        RW_APPEND
        RW_CASE
        RW_WHEN
        RW_THEN
        RW_ELSE
        RW_END
        RW_PACK
        RW_ZAP
        RW_REINDEX
        RW_RANGE
        RW_USING
        RW_FIELDS
        RW_TO
        RW_RANGE
        RW_TO
        RW_TOP

%type <string>

%%

sql : select_statement        { fAnalizer.Statement := ssSelect;      }
    | transform_statement     { fAnalizer.Statement := ssSelect;      }
    | union_statement         { fAnalizer.Statement := ssUnion;       }
    | update_statement        { fAnalizer.Statement := ssUpdate;      }
    | delete_statement        { fAnalizer.Statement := ssDelete;      }
    | insert_statement        { fAnalizer.Statement := ssInsert;      }
    | createtable_statement   { fAnalizer.Statement := ssCreateTable; }
    | altertable_statement    { fAnalizer.Statement := ssAlterTable; }
    | createindex_statement   { fAnalizer.Statement := ssCreateIndex; }
    | droptable_statement     { fAnalizer.Statement := ssDropTable;   }
    | dropindex_statement     { fAnalizer.Statement := ssDropIndex;   }
    | packtable_statement     { fAnalizer.Statement := ssPacktable;    }
    | zaptable_statement      { fAnalizer.Statement := ssZapTable;     }
    | reindextable_statement  { fAnalizer.Statement := ssReindexTable; }
    ;

/*  SELECT statement */
select_statement : select_clause from_clause where_clause userdef_range_clause
                   groupby_clause orderby_clause for_copy_append end_statement
                 ;

union_statement : select_statement RW_UNION second_select_statement end_statement
                ;

for_copy_append : /* empty */
                | RW_INTO _IDENTIFIER RW_FOR RW_APPEND
                  { CurrentAnalizer.IntoTable:= $<string>2; }
                ;

/* SELECT clause */
select_clause : select_case _MULT
                { CurrentAnalizer.DoSelectAll := True;
                  CurrentAnalizer.AddFieldIfNot('*');}
              | select_case list_expr_field
              ;

select_case : topn_groupby RW_SELECT topn_select
            | topn_groupby RW_SELECT topn_select RW_DISTINCT
              {CurrentAnalizer.IsDistinct:= True;}
            ;

topn_select : /* empty */
            | RW_TOP _UINTEGER
              { CurrentAnalizer.TopNInSelect:= StrToInt( $<string>2 ) ; }
            ;

topn_groupby : /* empty */
             | RW_TOP _UINTEGER
               { CurrentAnalizer.TopNInGroupBy:= StrToInt( $<string>2 ) ; }
             ;

list_expr_field : expr_field
                | list_expr_field _COMA expr_field

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -