Honestly, I don't see an issue with adding a field to store the salt. Or you could store the salt in the database field similar to how bcrypt does it: $version$salt$hash
.
This^ is the easiest way to prevent creating a security issue. This should be the answer to the question, and if this is possible, this is by far the most recommended way.
But since you asked...
Rainbow tables trade memory for time. By creating a large lookup table, you have to generate the table only once and apply it many times (this saves time) but it requires more storage. If the attacker needs to generate a custom rainbow table for your database, there is no real benefit to a rainbow table.
A salt also protects from another 'attack': you can see which users have the same password. That is, users within your user database table, but also globally: if anyone ever used pbkdf2 with the same settings, their value for the password correct horse battery staple
will match your record if anyone uses that password. If you have no unique field (other than the password) in your database, then the passwords must be unique within your database and you only need to protect from matching passwords in other databases.
The best way to do this is by using a pepper value. This is a randomly generated secret that you mix in with the password and ensures that your hashes are unique to your database. It also means that an attacker needs both the hashes and the pepper in order to crack any of the passwords. Without the pepper, assuming the pepper is strong enough (e.g. 128 bits of entropy), they will not even be able to crack the password "123456". A salt is unique per user and not secret, but a pepper is the same for all users and secret. It is usually best to apply both a salt and a pepper to stored passwords (NIST recommends that since 2017).
One safe way to mix in a pepper with a password is by using an HMAC:
password = hmac(password, pepper, algo="sha256")
To generate your pepper, you could use a regular password generator and generate a very long password. Make sure it uses a cryptographically secure random engine. The most popular and open source password managers do this.
If possible, the pepper should be stored separately from the passwords. If the passwords are stolen, the pepper might not be, and the passwords would remain safe. Since passwords are commonly in a database (like MariaDB), the pepper is commonly stored in a config file:
password = hmac(password, read_file("/etc/example/pepper"), algo="sha256")
password = pbkdf2(password, ...parameters)
if password == mariadb_query('select password from users where...') then ...
But this may be different in your situation, since you don't have usernames (or any other unique field) which is rather odd.
See also: Why do we authenticate by prompting a user to enter both username and password? Does prompting the password only suffice?
As for your proposal to use the password as salt, that only helps insofar as the password is unique. If you can guarantee the password is globally unique (and therefore also very strong, otherwise you cannot guarantee that), there is no point doing PBKDF2 anyway (any safe hash function will do, even MD5 if I'm not mistaken (of course, never ever use MD5 unless you travel back in time to before SHA2)). But if you cannot absolutely guarantee that the passwords are unique and strong enough to be uncrackable with a single pass of a fast hash function, then it's also not a good idea to use the password as salt. The whole point of a salt is to make your hashed value unique, and this defeats that purpose. Anyone who uses PBKDF2 with the password as salt, will have the same value for the same password. If using the password as salt was a good thing to do, we'd already be making our lives easy.