protected void parseTableConstraint( DdlTokenStream tokens,
                                         AstNode tableNode,
                                         boolean isAlterTable ) throws ParsingException {
        assert tokens != null;
        assert tableNode != null;

        String mixinType = isAlterTable ? TYPE_ADD_TABLE_CONSTRAINT_DEFINITION : TYPE_TABLE_CONSTRAINT;

        /*
        <table constraint definition> ::=
            [ <constraint name definition> ]
            <table constraint> [ <constraint attributes> ]
        
        <table constraint> ::=
              <unique constraint definition>
            | <referential constraint definition>
            | <check constraint definition>
            
        <constraint attributes> ::=
              <constraint check time> [ [ NOT ] DEFERRABLE ]
            | [ NOT ] DEFERRABLE [ <constraint check time> ]
        
        <unique constraint definition> ::=
                    <unique specification> even in SQL3)
            <unique specification>
              <left paren> <unique column list> <right paren>
        
        <unique column list> ::= <column name list>
        
        <referential constraint definition> ::=
            FOREIGN KEY
                <left paren> <referencing columns> <right paren>
              <references specification>
        
        <referencing columns> ::=
            <reference column list>
            
        <constraint attributes> ::=
              <constraint check time> [ [ NOT ] DEFERRABLE ]
            | [ NOT ] DEFERRABLE [ <constraint check time> ]
        
        <constraint check time> ::=
              INITIALLY DEFERRED
            | INITIALLY IMMEDIATE
            
        <check constraint definition> ::=
            CHECK
                <left paren> <search condition> <right paren>
         */
        consumeComment(tokens);

        if ((tokens.matches("PRIMARY", "KEY")) || (tokens.matches("FOREIGN", "KEY")) || (tokens.matches("UNIQUE"))) {

            // This is the case where the PK/FK/UK is NOT NAMED
            if (tokens.matches("UNIQUE")) {
                String uc_name = "UC_1"; // UNIQUE CONSTRAINT NAME
                tokens.consume(); // UNIQUE

                AstNode constraintNode = nodeFactory().node(uc_name, tableNode, mixinType);
                constraintNode.setProperty(CONSTRAINT_TYPE, UNIQUE);

                // CONSUME COLUMNS
                parseColumnNameList(tokens, constraintNode, TYPE_COLUMN_REFERENCE);

                parseConstraintAttributes(tokens, constraintNode);

                consumeComment(tokens);
            } else if (tokens.matches("PRIMARY", "KEY")) {
                String pk_name = "PK_1"; // PRIMARY KEY NAME
                tokens.consume("PRIMARY", "KEY"); // PRIMARY KEY

                AstNode constraintNode = nodeFactory().node(pk_name, tableNode, mixinType);
                constraintNode.setProperty(CONSTRAINT_TYPE, PRIMARY_KEY);

                // CONSUME COLUMNS
                parseColumnNameList(tokens, constraintNode, TYPE_COLUMN_REFERENCE);

                parseConstraintAttributes(tokens, constraintNode);

                consumeComment(tokens);
            } else if (tokens.matches("FOREIGN", "KEY")) {
                String fk_name = "FK_1"; // FOREIGN KEY NAME
                tokens.consume("FOREIGN", "KEY"); // FOREIGN KEY

                if (!tokens.matches(L_PAREN)) {
                    // Assume the FK is Named here
                    fk_name = tokens.consume();
                }

                AstNode constraintNode = nodeFactory().node(fk_name, tableNode, mixinType);
                constraintNode.setProperty(CONSTRAINT_TYPE, FOREIGN_KEY);

                // CONSUME COLUMNS
                parseColumnNameList(tokens, constraintNode, TYPE_COLUMN_REFERENCE);

                // Parse the references to table and columns
                parseReferences(tokens, constraintNode);

                parseConstraintAttributes(tokens, constraintNode);

                consumeComment(tokens);
            }
        } else if (tokens.matches(CONSTRAINT, TokenStream.ANY_VALUE, "UNIQUE")) {
            // CONSTRAINT P_KEY_2a UNIQUE (PERMISSIONUID)
            tokens.consume(); // CONSTRAINT
            String uc_name = parseName(tokens); // UNIQUE CONSTRAINT NAME
            tokens.consume("UNIQUE"); // UNIQUE

            AstNode constraintNode = nodeFactory().node(uc_name, tableNode, mixinType);
            constraintNode.setProperty(CONSTRAINT_TYPE, UNIQUE);

            // CONSUME COLUMNS
            parseColumnNameList(tokens, constraintNode, TYPE_COLUMN_REFERENCE);

            parseConstraintAttributes(tokens, constraintNode);

            consumeComment(tokens);
        } else if (tokens.matches(CONSTRAINT, TokenStream.ANY_VALUE, "PRIMARY", "KEY")) {
            // CONSTRAINT U_KEY_2a PRIMARY KEY (PERMISSIONUID)
            tokens.consume(CONSTRAINT); // CONSTRAINT
            String pk_name = parseName(tokens); // PRIMARY KEY NAME
            tokens.consume("PRIMARY", "KEY"); // PRIMARY KEY

            AstNode constraintNode = nodeFactory().node(pk_name, tableNode, mixinType);
            constraintNode.setProperty(CONSTRAINT_TYPE, PRIMARY_KEY);

            // CONSUME COLUMNS
            parseColumnNameList(tokens, constraintNode, TYPE_COLUMN_REFERENCE);

            parseConstraintAttributes(tokens, constraintNode);

            consumeComment(tokens);

        } else if (tokens.matches(CONSTRAINT, TokenStream.ANY_VALUE, "FOREIGN", "KEY")) {
            // CONSTRAINT F_KEY_2a FOREIGN KEY (PERMISSIONUID)
            tokens.consume(CONSTRAINT); // CONSTRAINT
            String fk_name = parseName(tokens); // FOREIGN KEY NAME
            tokens.consume("FOREIGN", "KEY"); // FOREIGN KEY

            AstNode constraintNode = nodeFactory().node(fk_name, tableNode, mixinType);

            constraintNode.setProperty(CONSTRAINT_TYPE, FOREIGN_KEY);

            // CONSUME COLUMNS
            parseColumnNameList(tokens, constraintNode, TYPE_COLUMN_REFERENCE);

            // Parse the references to table and columns
            parseReferences(tokens, constraintNode);

            parseConstraintAttributes(tokens, constraintNode);

            consumeComment(tokens);

        } else if (tokens.matches(CONSTRAINT, TokenStream.ANY_VALUE, CHECK)) {
            // CONSTRAINT zipchk CHECK (char_length(zipcode) = 5);
            tokens.consume(CONSTRAINT); // CONSTRAINT
            String ck_name = parseName(tokens); // NAME
            parseCheckConstraint(tokens, tableNode, mixinType, ck_name);
        }  else if (tokens.matches(CHECK)) {
             parseCheckConstraint(tokens, tableNode, mixinType, UNNAMED_CHECK_NODE_NAME);
        }
    }
protected void parseTableConstraint ( DdlTokenStream tokens , AstNode tableNode , boolean isAlterTable ) throws ParsingException { assert tokens != null ; assert tableNode != null ; String mixinType = isAlterTable ? TYPE_ADD_TABLE_CONSTRAINT_DEFINITION : TYPE_TABLE_CONSTRAINT ; consumeComment ( tokens ) ; if ( ( tokens . matches ( "PRIMARY" , "KEY" ) ) || ( tokens . matches ( "FOREIGN" , "KEY" ) ) || ( tokens . matches ( "UNIQUE" ) ) ) { if ( tokens . matches ( "UNIQUE" ) ) { String uc_name = "UC_1" ; tokens . consume ( ) ; AstNode constraintNode = nodeFactory ( ) . node ( uc_name , tableNode , mixinType ) ; constraintNode . setProperty ( CONSTRAINT_TYPE , UNIQUE ) ; parseColumnNameList ( tokens , constraintNode , TYPE_COLUMN_REFERENCE ) ; parseConstraintAttributes ( tokens , constraintNode ) ; consumeComment ( tokens ) ; } else if ( tokens . matches ( "PRIMARY" , "KEY" ) ) { String pk_name = "PK_1" ; tokens . consume ( "PRIMARY" , "KEY" ) ; AstNode constraintNode = nodeFactory ( ) . node ( pk_name , tableNode , mixinType ) ; constraintNode . setProperty ( CONSTRAINT_TYPE , PRIMARY_KEY ) ; parseColumnNameList ( tokens , constraintNode , TYPE_COLUMN_REFERENCE ) ; parseConstraintAttributes ( tokens , constraintNode ) ; consumeComment ( tokens ) ; } else if ( tokens . matches ( "FOREIGN" , "KEY" ) ) { String fk_name = "FK_1" ; tokens . consume ( "FOREIGN" , "KEY" ) ; if ( ! tokens . matches ( L_PAREN ) ) { fk_name = tokens . consume ( ) ; } AstNode constraintNode = nodeFactory ( ) . node ( fk_name , tableNode , mixinType ) ; constraintNode . setProperty ( CONSTRAINT_TYPE , FOREIGN_KEY ) ; parseColumnNameList ( tokens , constraintNode , TYPE_COLUMN_REFERENCE ) ; parseReferences ( tokens , constraintNode ) ; parseConstraintAttributes ( tokens , constraintNode ) ; consumeComment ( tokens ) ; } } else if ( tokens . matches ( CONSTRAINT , TokenStream . ANY_VALUE , "UNIQUE" ) ) { tokens . consume ( ) ; String uc_name = parseName ( tokens ) ; tokens . consume ( "UNIQUE" ) ; AstNode constraintNode = nodeFactory ( ) . node ( uc_name , tableNode , mixinType ) ; constraintNode . setProperty ( CONSTRAINT_TYPE , UNIQUE ) ; parseColumnNameList ( tokens , constraintNode , TYPE_COLUMN_REFERENCE ) ; parseConstraintAttributes ( tokens , constraintNode ) ; consumeComment ( tokens ) ; } else if ( tokens . matches ( CONSTRAINT , TokenStream . ANY_VALUE , "PRIMARY" , "KEY" ) ) { tokens . consume ( CONSTRAINT ) ; String pk_name = parseName ( tokens ) ; tokens . consume ( "PRIMARY" , "KEY" ) ; AstNode constraintNode = nodeFactory ( ) . node ( pk_name , tableNode , mixinType ) ; constraintNode . setProperty ( CONSTRAINT_TYPE , PRIMARY_KEY ) ; parseColumnNameList ( tokens , constraintNode , TYPE_COLUMN_REFERENCE ) ; parseConstraintAttributes ( tokens , constraintNode ) ; consumeComment ( tokens ) ; } else if ( tokens . matches ( CONSTRAINT , TokenStream . ANY_VALUE , "FOREIGN" , "KEY" ) ) { tokens . consume ( CONSTRAINT ) ; String fk_name = parseName ( tokens ) ; tokens . consume ( "FOREIGN" , "KEY" ) ; AstNode constraintNode = nodeFactory ( ) . node ( fk_name , tableNode , mixinType ) ; constraintNode . setProperty ( CONSTRAINT_TYPE , FOREIGN_KEY ) ; parseColumnNameList ( tokens , constraintNode , TYPE_COLUMN_REFERENCE ) ; parseReferences ( tokens , constraintNode ) ; parseConstraintAttributes ( tokens , constraintNode ) ; consumeComment ( tokens ) ; } else if ( tokens . matches ( CONSTRAINT , TokenStream . ANY_VALUE , CHECK ) ) { tokens . consume ( CONSTRAINT ) ; String ck_name = parseName ( tokens ) ; parseCheckConstraint ( tokens , tableNode , mixinType , ck_name ) ; } else if ( tokens . matches ( CHECK ) ) { parseCheckConstraint ( tokens , tableNode , mixinType , UNNAMED_CHECK_NODE_NAME ) ; } }
Parses full table constraint definition including the "CONSTRAINT" token Examples: CONSTRAINT P_KEY_2a UNIQUE
(PERMISSIONUID)

@param tokens the {@link DdlTokenStream} representing the tokenized DDL content; may not be null
@param tableNode
@param isAlterTable true if in-line constraint is part of add column in alter table statement
@throws ParsingException