Beispiel #1
0
db_lookup_retval_t SqlParser::parseSql(std::set<std::string> &dbs, int *txLevel, bool parseMaster) {
    dbs.clear();

    StringVector tables, aliases;

    if (getTokensLen() <= 0) {
        log_warning("empty sql for dababase lookup!\n");
        return RET_ERROR_UNPARSABLE;
    }

    switch (getTokenId(0)) {
        case TK_SQL_SELECT:
        {
            int usemaster = 0;
            if (parseMaster) usemaster = 1;
            // special handling for our get unique id function call.
            if (getTokensLen() > 1 && getTokenStr(1) == "get_next_id")
                return RET_USE_DEFAULT_DATABASE;

            int fromStart, fromEnd;

            if (!getSqlFrom(0, &fromStart, &fromEnd)) {
                if ((getTokensLen() > 3 && getTokenId(1) == TK_LITERAL &&
                        getTokenId(2) == TK_OBRACE) ||
                        (getTokensLen() == 2 && getTokenId(1) == TK_LITERAL)) {

                    // for special stored procedures
                    return RET_USE_ALL_PARTITIONS;
                }

                printTokens("no FROM found, using default db: ");
                return RET_USE_DEFAULT_DATABASE;
            }

            if (!parseTableNameAndAlias(fromStart, fromEnd, tables, aliases)) {
                printTokens("could not parse table alias, using default db: ");
                return RET_USE_DEFAULT_DATABASE;
            }

            // for non-partitioned tables, we can use any db
            // since each db should have a view of it
            bool partitioned = false;
            for (size_t i = 0; i < tables.size(); i++) {
                if (dbPart->isPartitionedTable(tables[i])) {
                    partitioned = true;
                    break;
                }
            }
            if (!setDefaultLimit()) {
                printTokens("error in modifying LIMIT: ");
                return RET_ERROR_UNPARSABLE;
            }
            /*
               if (!partitioned)
               return ((*txLevel) > 0 ? RET_USE_DEFAULT_DATABASE : RET_USE_ANY_PARTITION);
             */
            int whereStart, whereEnd;
            if (!getSqlWhere(fromEnd, &whereStart, &whereEnd)) {
                // add LIMIT, change the offset to 0 if needed
                uint64_t aa = 0;
                dbPart->getPartitionNum(tables[0], &aa);

                for (size_t i = 0; i < aa; i++) {
                    std::string db;
                    getDbMapping(tables[0], "", i, db, usemaster, 0);
                    if (!db.empty())
                        dbs.insert(db);
                }
                return RET_USE_ALL_PARTITIONS;
            }

            for (size_t i = 0; i < tables.size(); i++) {
                std::string partitionKey;
                getPartitionKey(tables[i], partitionKey);
                if (partitionKey.empty()) {
                    std::string db;
                    getDbMapping(tables[i], "", 0, db, usemaster, 0);
                    if (!db.empty())
                        dbs.insert(db);
                    continue;
                }


                std::vector<uint64_t> keyValues;
                if (!findPartitionKeyValue(whereStart, whereEnd, tables[i],
                        aliases[i], partitionKey, keyValues)) {
                    printTokens("unrecognized key ranges: ");
                    return RET_ERROR_UNPARSABLE;
                }
                if (keyValues.size() == 0) {
                    uint64_t aa = 0;
                    dbPart->getPartitionNum(tables[0], &aa);

                    for (size_t i = 0; i < aa; i++) {
                        std::string db;
                        getDbMapping(tables[0], "", i, db, usemaster, 0);
                        if (!db.empty())
                            dbs.insert(db);
                    }
                    return RET_USE_ALL_PARTITIONS;
                }

                // find the db partition for all the IDs
                for (size_t k = 0; k < keyValues.size(); k++) {
                    std::string db;
                    getDbMapping(tables[i], partitionKey, keyValues[k], db, usemaster, 0);
                    if (!db.empty())
                        dbs.insert(db);
                }
            }



            if (dbs.empty())
                return RET_USE_ALL_PARTITIONS;

            return RET_DB_LOOKUP_SUCCESS;
        }
        case TK_SQL_UPDATE:
        {
            int setPos;
            if (!findToken(0, getTokensLen(), TK_SQL_SET, &setPos)) {
                printTokens("could not find SET in UPDATE: ");
                return RET_ERROR_UNPARSABLE;
            };

            if (getTokenId(setPos - 1) != TK_LITERAL) {
                printTokens("expecting table name before SET: ");
                return RET_ERROR_UNPARSABLE;
            }

            std::string table = getTokenStr(setPos - 1);

            // for nonpartitioned tables, update the default master db
            if (!(dbPart->isPartitionedTable(table))) {
                std::string db;
                getDbMapping(table, "", 0, db, 1, 0);
                if (!db.empty())
                    dbs.insert(db);
                return RET_USE_ALL_PARTITIONS;
            }

            int whereStart, whereEnd;
            if (!getSqlWhere(setPos + 1, &whereStart, &whereEnd)) {
                printTokens("no WHERE found: ");
                return RET_ERROR_UNPARSABLE;
            }

            std::string partitionKey;
            getPartitionKey(table, partitionKey);

            g_assert(!partitionKey.empty());

            std::vector<uint64_t> keyValues;
            if (!findPartitionKeyValue(whereStart, whereEnd, table, "",
                    partitionKey, keyValues)) {
                printTokens("unrecognized ranges: ");
                return RET_ERROR_UNPARSABLE;
            }

            // find the db partition for all the IDs
            for (size_t k = 0; k < keyValues.size(); k++) {
                std::string db;
                getDbMapping(table, partitionKey, keyValues[k], db, 1, 0);
                if (!db.empty())
                    dbs.insert(db);
            }

            if (dbs.empty())
                return RET_USE_ALL_PARTITIONS;

            return RET_DB_LOOKUP_SUCCESS;
        }
        case TK_SQL_INSERT:
        { // support format: INSERT  ... <table> (...) VALUES (....)

            int pos;
            uint64_t insertid = 0;
            if (!findToken(1, getTokensLen(), TK_LITERAL, &pos)) {
                printTokens("could not find table name: ");
                return RET_ERROR_UNPARSABLE;
            }

            std::string table = getTokenStr(pos);

            std::string partitionKey;
            getPartitionKey(table, partitionKey);

            if (getTokenId(++pos) != TK_OBRACE) {
                printTokens("unrecognized INSERT: ");
                return RET_ERROR_UNPARSABLE;
            }

            pos++;

            std::string autoIncrementColumn;
            dbPart->getAutoIncrementColumn(table, autoIncrementColumn);

            int keyPos = -1;
            int autoColPos = -1;
            for (int i = pos; i < getTokensLen(); i++) {
                if ((getTokenId(i) == TK_CBRACE) ||
                        (autoColPos >= 0 && keyPos >= 0))
                    break;
                if (getTokenId(i) == TK_LITERAL &&
                        tokComp(i, partitionKey) == 0) {
                    keyPos = i - pos;
                    continue;
                }
                if (getTokenId(i) == TK_LITERAL &&
                        tokComp(i, autoIncrementColumn) == 0) {
                    autoColPos = i - pos;
                }
            }

            if ((!partitionKey.empty()) && keyPos == -1 && partitionKey != autoIncrementColumn) {
                log_warning("could not find the partition key %s:", partitionKey.c_str());
                printTokens();
                return RET_ERROR_UNPARSABLE;
            }

            if ((!partitionKey.empty()) && keyPos == -1) {
                // special handling for the case in which partition key type is auto increment.
                // need to get the id first and then modify the INSERT
                uint64_t id;
                if (!dbPart->getNextUniqueId(table, &id)) {
                    log_warning("could not get next unique id for %s", partitionKey.c_str());
                    printTokens();
                    return RET_DB_LOOKUP_ERROR;
                }
                insertid = id;
                std::string db;
                getDbMapping(table, partitionKey, id, db, 1, id);
                if (!db.empty())
                    dbs.insert(db);
                else {
                    printTokens("could not find db for id %d: ");
                    return RET_DB_LOOKUP_ERROR;
                }

                if (modifySqlForInsert(partitionKey, id)) {
                    if (partitionKey == autoIncrementColumn || autoIncrementColumn.empty())
                        return RET_DB_LOOKUP_SUCCESS;
                } else {
                    log_warning("could not insert id for %s ", partitionKey.c_str());
                    printTokens();
                    return RET_DB_LOOKUP_ERROR;
                }
            }

            if (!autoIncrementColumn.empty() && autoColPos < 0 && (partitionKey != autoIncrementColumn)) {
                // need to get unique ids for auto increment columns
                uint64_t id;
                if (!dbPart->getNextUniqueId(table, &id)) {
                    log_warning("could not get next unique id for %s", autoIncrementColumn.c_str());
                    printTokens();
                    return RET_DB_LOOKUP_ERROR;
                }
                insertid = id;
                if (modifySqlForInsert(autoIncrementColumn, id)) {
                    // for nonparitioned table INSERT, use the default master db
                    if (partitionKey.empty())
                        return RET_USE_DEFAULT_DATABASE;

                    if (keyPos == -1)
                        return RET_DB_LOOKUP_SUCCESS;
                } else {
                    log_warning("could not insert id for %s ", autoIncrementColumn.c_str());
                    printTokens();
                    return RET_DB_LOOKUP_ERROR;
                }
            }

            // for nonparitioned table INSERT, use the default master db
            if (partitionKey.empty()) {
                std::string db;
                getDbMapping(table, "", 0, db, 1, insertid);
                if (!db.empty())
                    dbs.insert(db);
                return RET_USE_ALL_PARTITIONS;
            }

            pos += keyPos;

            int valPos;

            if (!findToken(pos, getTokensLen(), TK_SQL_VALUES, &valPos)) {
                printTokens("VALUES is not found: ");
                return RET_ERROR_UNPARSABLE;
            }

            if (getTokenId(valPos + 1) != TK_OBRACE) {
                printTokens("expecting '(' after VALUES: ");
                return RET_ERROR_UNPARSABLE;
            }

            pos = valPos + 2 + keyPos;
            if (pos < getTokensLen()) {//dqm
                //if (pos < getTokensLen() && getTokenId(pos) == TK_INTEGER) {
                uint64_t id = tokenToUint64(pos);
                std::string db;
                getDbMapping(table, partitionKey, id, db, 1, insertid);
                if (!db.empty())
                    dbs.insert(db);

                if (dbs.empty()) {
                    printTokens("could not find db mapping: ");
                    return RET_ERROR_UNPARSABLE;
                }

                return RET_DB_LOOKUP_SUCCESS;
            } else {
                log_warning("could not recognize value for %s:", partitionKey.c_str());
                printTokens();
                return RET_ERROR_UNPARSABLE;
            }

            break;
        }
        
        case TK_SQL_REPLACE:
        { // support format: replace  ... <table> (...) VALUES (....)

            int pos;
            uint64_t insertid = 0;
            if (!findToken(1, getTokensLen(), TK_LITERAL, &pos)) {
                printTokens("could not find table name: ");
                return RET_ERROR_UNPARSABLE;
            }

            std::string table = getTokenStr(pos);

            std::string partitionKey;
            getPartitionKey(table, partitionKey);

            if (getTokenId(++pos) != TK_OBRACE) {
                printTokens("unrecognized INSERT: ");
                return RET_ERROR_UNPARSABLE;
            }

            pos++;

            std::string autoIncrementColumn;
            dbPart->getAutoIncrementColumn(table, autoIncrementColumn);

            int keyPos = -1;
            int autoColPos = -1;
            for (int i = pos; i < getTokensLen(); i++) {
                if ((getTokenId(i) == TK_CBRACE) ||
                        (autoColPos >= 0 && keyPos >= 0))
                    break;
                if (getTokenId(i) == TK_LITERAL &&
                        tokComp(i, partitionKey) == 0) {
                    keyPos = i - pos;
                    continue;
                }
                if (getTokenId(i) == TK_LITERAL &&
                        tokComp(i, autoIncrementColumn) == 0) {
                    autoColPos = i - pos;
                }
            }

            if ((!partitionKey.empty()) && keyPos == -1 && partitionKey != autoIncrementColumn) {
                log_warning("could not find the partition key %s:", partitionKey.c_str());
                printTokens();
                return RET_ERROR_UNPARSABLE;
            }

            if ((!partitionKey.empty()) && keyPos == -1) {
                // special handling for the case in which partition key type is auto increment.
                // need to get the id first and then modify the INSERT
                uint64_t id;
                if (!dbPart->getNextUniqueId(table, &id)) {
                    log_warning("could not get next unique id for %s", partitionKey.c_str());
                    printTokens();
                    return RET_DB_LOOKUP_ERROR;
                }
                insertid = id;
                std::string db;
                getDbMapping(table, partitionKey, id, db, 1, id);
                if (!db.empty())
                    dbs.insert(db);
                else {
                    printTokens("could not find db for id %d: ");
                    return RET_DB_LOOKUP_ERROR;
                }

                if (modifySqlForInsert(partitionKey, id)) {
                    if (partitionKey == autoIncrementColumn || autoIncrementColumn.empty())
                        return RET_DB_LOOKUP_SUCCESS;
                } else {
                    log_warning("could not insert id for %s ", partitionKey.c_str());
                    printTokens();
                    return RET_DB_LOOKUP_ERROR;
                }
            }

            if (!autoIncrementColumn.empty() && autoColPos < 0 && (partitionKey != autoIncrementColumn)) {
                // need to get unique ids for auto increment columns
                uint64_t id;
                if (!dbPart->getNextUniqueId(table, &id)) {
                    log_warning("could not get next unique id for %s", autoIncrementColumn.c_str());
                    printTokens();
                    return RET_DB_LOOKUP_ERROR;
                }
                insertid = id;
                if (modifySqlForInsert(autoIncrementColumn, id)) {
                    // for nonparitioned table INSERT, use the default master db
                    if (partitionKey.empty())
                        return RET_USE_DEFAULT_DATABASE;

                    if (keyPos == -1)
                        return RET_DB_LOOKUP_SUCCESS;
                } else {
                    log_warning("could not insert id for %s ", autoIncrementColumn.c_str());
                    printTokens();
                    return RET_DB_LOOKUP_ERROR;
                }
            }

            // for nonparitioned table INSERT, use the default master db
            if (partitionKey.empty()) {
                std::string db;
                getDbMapping(table, "", 0, db, 1, insertid);
                if (!db.empty())
                    dbs.insert(db);
                return RET_USE_ALL_PARTITIONS;
            }

            pos += keyPos;

            int valPos;

            if (!findToken(pos, getTokensLen(), TK_SQL_VALUES, &valPos)) {
                printTokens("VALUES is not found: ");
                return RET_ERROR_UNPARSABLE;
            }

            if (getTokenId(valPos + 1) != TK_OBRACE) {
                printTokens("expecting '(' after VALUES: ");
                return RET_ERROR_UNPARSABLE;
            }

            pos = valPos + 2 + keyPos;
            if (pos < getTokensLen()) {//dqm
                //if (pos < getTokensLen() && getTokenId(pos) == TK_INTEGER) {
                uint64_t id = tokenToUint64(pos);
                std::string db;
                getDbMapping(table, partitionKey, id, db, 1, insertid);
                if (!db.empty())
                    dbs.insert(db);

                if (dbs.empty()) {
                    printTokens("could not find db mapping: ");
                    return RET_ERROR_UNPARSABLE;
                }

                return RET_DB_LOOKUP_SUCCESS;
            } else {
                log_warning("could not recognize value for %s:", partitionKey.c_str());
                printTokens();
                return RET_ERROR_UNPARSABLE;
            }

            break;
        }

        case TK_SQL_ALTER:
        {
            std::string tableName;
            if (getTokensLen() >= 3 && getTokenId(1) == TK_SQL_TABLE) {
                tableName = getTokenStr(2);
            } else if (getTokensLen() >= 4 && getTokenId(1) == TK_SQL_IGNORE &&
                    getTokenId(2) == TK_SQL_TABLE) {
                tableName = getTokenStr(3);
            } else
                break;
            if (dbPart->isPartitionedTable(tableName))
                return RET_USE_ALL_PARTITIONS;
            else
                return RET_USE_DEFAULT_DATABASE;
        }

        case TK_SQL_CALL:
        {
            return RET_USE_ALL_PARTITIONS;
        }

        case TK_SQL_SHOW:
        {
            if (getTokensLen() == 4 && getTokenId(2) == TK_SQL_FROM &&
                    strcasecmp(getTokenStr(1).c_str(), "fields") == 0) {

                if (dbPart->isPartitionedTable(getTokenStr(3))) {
                    return RET_USE_ANY_PARTITION;
                }
                return RET_USE_DEFAULT_DATABASE;
            }

            if (getTokensLen() == 2 &&
                    strcasecmp(getTokenStr(1).c_str(), "tables") == 0) {

                //special handling for show tables;
                //
                std::string sql = "select table_name ";
                sql.append(" from kind_setting order by table_name");
                g_string_truncate(inputSql, NET_HEADER_SIZE + 1);
                g_string_append_len(inputSql, sql.data(), sql.size());

                network_mysqld_proto_set_header_len((unsigned char *) (inputSql->str),
                        inputSql->len - NET_HEADER_SIZE);

                return RET_USE_DEFAULT_DATABASE;
            } else
                return RET_USE_DEFAULT_DATABASE;

            break;
        }

        case TK_SQL_DELETE:
        {
            int fromPos;
            if (!findToken(1, getTokensLen(), TK_SQL_FROM, &fromPos)) {
                printTokens("could not find FROM in DELETE: ");
                return RET_ERROR_UNPARSABLE;
            };

            if (fromPos >= getTokensLen() - 1) {
                printTokens("could not find table name in DELETE: ");
                return RET_ERROR_UNPARSABLE;
            }

            std::string table = getTokenStr(fromPos + 1);
            // for nonpartitioned tables, update the default master db
            if (!(dbPart->isPartitionedTable(table))) {
                std::string db;
                getDbMapping(table, "", 0, db, 1, 0);
                if (!db.empty())
                    dbs.insert(db);
                return RET_USE_ALL_PARTITIONS;
            }

            int whereStart, whereEnd;
            if (!getSqlWhere(fromPos + 1, &whereStart, &whereEnd)) {
                printTokens("no WHERE found: ");
                return RET_ERROR_UNPARSABLE;
            }

            std::string partitionKey;
            getPartitionKey(table, partitionKey);

            g_assert(!partitionKey.empty());

            std::vector<uint64_t> keyValues;
            if (!findPartitionKeyValue(whereStart, whereEnd, table, "",
                    partitionKey, keyValues)) {
                printTokens("unrecognized ranges: ");
                return RET_ERROR_UNPARSABLE;
            }

            // find the db partition for all the IDs
            for (size_t k = 0; k < keyValues.size(); k++) {
                std::string db;
                getDbMapping(table, partitionKey, keyValues[k], db, 1, 0);
                if (!db.empty())
                    dbs.insert(db);
            }

            if (dbs.empty())
                return RET_USE_ALL_PARTITIONS;

            return RET_DB_LOOKUP_SUCCESS;
        }
        case TK_SQL_DESC:
        case TK_SQL_DESCRIBE:
        {
            if (getTokensLen() >= 2) {
                std::string tableName = getTokenStr(1);
                if (dbPart->isPartitionedTable(tableName))
                    return RET_USE_ANY_PARTITION;
                else
                    return RET_USE_DEFAULT_DATABASE;
            }

            return RET_ERROR_UNPARSABLE;
        }
        case TK_SQL_SET:
        {
            if ((getTokensLen() >= 4) &&
                    (getTokenId(1) == TK_SQL_AUTOCOMMIT) &&
                    (getTokenStr(3).compare("0") == 0)) {
                (*txLevel)++;
            }
            return RET_USE_ALL_DATABASES;
        }
        case TK_SQL_START:
        case TK_SQL_BEGIN:
        {
            (*txLevel)++;
            return RET_USE_ALL_DATABASES;
        }
        case TK_SQL_COMMIT:
        case TK_SQL_ROLLBACK:
        {
            (*txLevel)--;
            return RET_USE_ALL_DATABASES;
        }
        default:
        {
            break;
        }
    }

    printTokens("unrecognized query, using default master db: ");

    return RET_USE_DEFAULT_DATABASE;
}
 inline bool getDistributionKey() const { return getPartitionKey(); };