A "pure" function could instead work around it by returning (without executing) a query, accepting a state and returning a new, modified state, or otherwise returning some kind of commands to the caller without directly querying the database.
At least in Haskell due to lazyness this is (almost) always what happens. A monad is just one kind of deferred computation, with an operator >>= ("bind") that happens to prevent compiler reordering or deduplication. Any IO actions are only executed when main is evaluated and no earlier. Strict functional languages to my knowledge don't need monads to do IO since they don't have the same issues with evaluation order that Haskell does (though they might want them for type safety purposes).