| 1770 | }; |
| 1771 | |
| 1772 | static cell_t SQL_ExecuteTransaction(IPluginContext *pContext, const cell_t *params) |
| 1773 | { |
| 1774 | HandleSecurity sec(pContext->GetIdentity(), g_pCoreIdent); |
| 1775 | |
| 1776 | IDatabase *db = NULL; |
| 1777 | HandleError err = g_DBMan.ReadHandle(params[1], DBHandle_Database, (void **)&db); |
| 1778 | if (err != HandleError_None) |
| 1779 | return pContext->ThrowNativeError("Invalid database handle %x (error: %d)", params[1], err); |
| 1780 | |
| 1781 | Transaction *txn; |
| 1782 | if ((err = handlesys->ReadHandle(params[2], hTransactionType, &sec, (void **)&txn)) != HandleError_None) |
| 1783 | return pContext->ThrowNativeError("Invalid transaction handle %x (error %d)", params[2], err); |
| 1784 | |
| 1785 | if (!db->GetDriver()->IsThreadSafe()) |
| 1786 | return pContext->ThrowNativeError("Driver \"%s\" is not thread safe!", db->GetDriver()->GetIdentifier()); |
| 1787 | |
| 1788 | IPluginFunction *onSuccess = NULL; |
| 1789 | IPluginFunction *onError = NULL; |
| 1790 | if (!pContext->GetFunctionByIdOrNull(params[3], &onSuccess)) |
| 1791 | return 0; |
| 1792 | if (!pContext->GetFunctionByIdOrNull(params[4], &onError)) |
| 1793 | return 0; |
| 1794 | |
| 1795 | cell_t data = params[5]; |
| 1796 | PrioQueueLevel priority = PrioQueue_Normal; |
| 1797 | if (params[6] == (cell_t)PrioQueue_High) |
| 1798 | priority = PrioQueue_High; |
| 1799 | else if (params[6] == (cell_t)PrioQueue_Low) |
| 1800 | priority = PrioQueue_Low; |
| 1801 | |
| 1802 | TTransactOp *op = new TTransactOp(db, txn, params[2], pContext->GetIdentity(), onSuccess, onError, data); |
| 1803 | |
| 1804 | // The handle owns the underlying Transaction object, but we want to close |
| 1805 | // the plugin's view both to ensure reliable access for us and to prevent |
| 1806 | // further tampering on the main thread. To do this, TTransactOp clones the |
| 1807 | // transaction handle and automatically closes it. Therefore, it's safe to |
| 1808 | // close the plugin's handle here. |
| 1809 | handlesys->FreeHandle(params[2], &sec); |
| 1810 | |
| 1811 | IPlugin *pPlugin = scripts->FindPluginByContext(pContext); |
| 1812 | if (pPlugin->GetProperty("DisallowDBThreads", NULL) || !g_DBMan.AddToThreadQueue(op, priority)) |
| 1813 | { |
| 1814 | // Do everything right now. |
| 1815 | op->RunThreadPart(); |
| 1816 | op->RunThinkPart(); |
| 1817 | op->Destroy(); |
| 1818 | } |
| 1819 | |
| 1820 | return 0; |
| 1821 | } |
| 1822 | |
| 1823 | REGISTER_NATIVES(dbNatives) |
| 1824 | { |
nothing calls this directly
no test coverage detected