41_DatabaseDemo.lua 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. -- Database demo. This sample demonstrates how to use database subsystem to connect to a database and execute adhoc SQL statements.
  2. require "LuaScripts/Utilities/Sample"
  3. local connection
  4. local row
  5. local maxRows = 50
  6. function Start()
  7. -- Execute the common startup for samples
  8. SampleStart()
  9. -- Disable default execution of Lua from the console
  10. SetExecuteConsoleCommands(false)
  11. -- Subscribe to console commands and the frame update
  12. SubscribeToEvent("ConsoleCommand", "HandleConsoleCommand")
  13. SubscribeToEvent("Update", "HandleUpdate")
  14. -- Subscribe key down event
  15. SubscribeToEvent("KeyDown", "HandleEscKeyDown")
  16. -- Hide logo to make room for the console
  17. SetLogoVisible(false)
  18. -- Show the console by default, make it large
  19. console.numRows = graphics.height / 16
  20. console.numBufferedRows = 2 * console.numRows
  21. console.commandInterpreter = "LuaScriptEventInvoker"
  22. console.visible = true
  23. console.closeButton.visible = false
  24. -- Show OS mouse cursor
  25. input.mouseVisible = true
  26. -- Set the mouse mode to use in the sample
  27. SampleInitMouseMode(MM_FREE)
  28. -- Open the operating system console window (for stdin / stdout) if not open yet
  29. -- Do not open in fullscreen, as this would cause constant device loss
  30. if not graphics.fullscreen then
  31. OpenConsoleWindow()
  32. end
  33. -- In general, the connection string is really the only thing that need to be changed when switching underlying database API
  34. -- and that when using ODBC API then the connection string must refer to an already installed ODBC driver
  35. -- Although it has not been tested yet but the ODBC API should be able to interface with any vendor provided ODBC drivers
  36. -- In this particular demo, however, when using ODBC API then the SQLite-ODBC driver need to be installed
  37. -- The SQLite-ODBC driver can be built from source downloaded from http:--www.ch-werner.de/sqliteodbc/
  38. -- You can try to install other ODBC driver and modify the connection string below to match your ODBC driver
  39. -- Both DSN and DSN-less connection string should work
  40. -- The ODBC API, i.e. URHO3D_DATABASE_ODBC build option, is only available for native (including RPI) platforms
  41. -- and it is designed for development of game server connecting to ODBC-compliant databases in mind
  42. -- This demo will always work when using SQLite API as the SQLite database engine is embedded inside Urho3D game engine
  43. -- and this is also the case when targeting Web platform
  44. -- We could have used #ifdef to init the connection string during compile time, but below shows how it is done during runtime
  45. -- The "URHO3D_DATABASE_ODBC" compiler define is set when URHO3D_DATABASE_ODBC build option is enabled
  46. -- Connect to a temporary in-memory SQLite database
  47. connection = database:Connect(GetDBAPI() == DBAPI_ODBC and "Driver=SQLite3;Database=:memory:" or "file://")
  48. -- Subscribe to database cursor event to loop through query resultset
  49. SubscribeToEvent("DbCursor", "HandleDbCursor")
  50. -- Show instruction
  51. print([[This demo connects to temporary in-memory database.
  52. All the tables and their data will be lost after exiting the demo.
  53. Enter a valid SQL statement in the console input and press Enter to execute.
  54. Enter 'get/set maxrows [number]' to get/set the maximum rows to be printed out.
  55. Enter 'get/set connstr [string]' to get/set the database connection string and establish a new connection to it.
  56. Enter 'quit' or 'exit' to exit the demo.
  57. For example:]])
  58. HandleInput("create table tbl1(col1 varchar(10), col2 smallint)")
  59. HandleInput("insert into tbl1 values('Hello', 10)")
  60. HandleInput("insert into tbl1 values('World', 20)")
  61. HandleInput("select * from tbl1")
  62. end
  63. function HandleConsoleCommand(eventType, eventData)
  64. if eventData["Id"]:GetString() == "LuaScriptEventInvoker" then
  65. HandleInput(eventData["Command"]:GetString())
  66. end
  67. end
  68. function HandleUpdate(eventType, eventData)
  69. -- Check if there is input from stdin
  70. local input = GetConsoleInput()
  71. if input:len() > 0 then
  72. HandleInput(input)
  73. end
  74. end
  75. function HandleEscKeyDown(eventType, eventData)
  76. -- Unlike the other samples, exiting the engine when ESC is pressed instead of just closing the console
  77. if eventData["Key"]:GetInt() == KEY_ESCAPE then
  78. engine:Exit()
  79. end
  80. end
  81. function HandleDbCursor(eventType, eventData)
  82. -- In a real application the P_SQL can be used to do the logic branching in a shared event handler
  83. -- However, this is not required in this sample demo
  84. local colValues = eventData["ColValues"]:GetVariantVector()
  85. local colHeaders = eventData["ColHeaders"]:GetStringVector()
  86. -- In this sample demo we just use db cursor to dump each row immediately so we can filter out the row to conserve memory
  87. -- In a real application this can be used to perform the client-side filtering logic
  88. eventData["Filter"] = true
  89. -- In this sample demo we abort the further cursor movement when maximum rows being dumped has been reached
  90. row = row + 1
  91. eventData["Abort"] = row >= maxRows
  92. for i, colHeader in ipairs(colHeaders) do
  93. print("Row #" .. row .. ": " .. colHeader .. " = " .. colValues[i])
  94. end
  95. end
  96. function HandleInput(input)
  97. -- Echo input string to stdout
  98. print(input)
  99. row = 0
  100. if input == "quit" or input == "exit" then
  101. engine:Exit()
  102. elseif input:find("set") or input:find("get") then
  103. -- We expect a key/value pair for 'set' command
  104. local command, setting, value
  105. _, _, command, setting, value = input:find("([gs]et)%s*(%a*)%s*(.*)")
  106. if command == "set" and value ~= nil then
  107. if setting == "maxrows" then
  108. maxRows = Max(value, 1)
  109. elseif (setting == "connstr") then
  110. local newConnection = database:Connect(value)
  111. if newConnection ~= nil then
  112. database:Disconnect(connection)
  113. connection = newConnection
  114. end
  115. end
  116. end
  117. if setting ~= nil then
  118. if setting == "maxrows" then
  119. print("maximum rows is set to " .. maxRows)
  120. elseif setting == "connstr" then
  121. print("connection string is set to " .. connection.connectionString)
  122. else
  123. print("Unrecognized setting: " .. setting)
  124. end
  125. else
  126. print("Missing setting paramater. Recognized settings are: maxrows, connstr")
  127. end
  128. else
  129. -- In this sample demo we use the dbCursor event to loop through each row as it is being fetched
  130. -- Regardless of this event is being used or not, all the fetched rows will be made available in the DbResult object,
  131. -- unless the dbCursor event handler has instructed to filter out the fetched row from the final result
  132. local result = connection:Execute(input, true)
  133. -- Number of affected rows is only meaningful for DML statements like insert/update/delete
  134. if result.numAffectedRows ~= -1 then
  135. print("Number of affected rows: " .. result.numAffectedRows)
  136. end
  137. end
  138. print(" ")
  139. end
  140. -- Create XML patch instructions for screen joystick layout specific to this sample app
  141. function GetScreenJoystickPatchString()
  142. return
  143. "<patch>" ..
  144. " <add sel=\"/element/element[./attribute[@name='Name' and @value='Button2']]\">" ..
  145. " <attribute name=\"Is Visible\" value=\"false\" />" ..
  146. " </add>" ..
  147. " <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" ..
  148. " <attribute name=\"Is Visible\" value=\"false\" />" ..
  149. " </add>" ..
  150. "</patch>"
  151. end