41_DatabaseDemo.as 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /// Database demo. This sample demonstrates how to use database subsystem to connect to a database and execute adhoc SQL statements.
  2. #include "Scripts/Utilities/Sample.as"
  3. DbConnection@ connection;
  4. uint row;
  5. uint maxRows = 50;
  6. void Start()
  7. {
  8. // Execute the common startup for samples
  9. SampleStart();
  10. // Disable default execution of AngelScript from the console
  11. script.executeConsoleCommands = false;
  12. // Subscribe to console commands and the frame update
  13. SubscribeToEvent("ConsoleCommand", "HandleConsoleCommand");
  14. SubscribeToEvent("Update", "HandleUpdate");
  15. // Subscribe key down event
  16. SubscribeToEvent("KeyDown", "HandleEscKeyDown");
  17. // Hide logo to make room for the console
  18. SetLogoVisible(false);
  19. // Show the console by default, make it large
  20. console.numRows = graphics.height / 16;
  21. console.numBufferedRows = 2 * console.numRows;
  22. console.commandInterpreter = "ScriptEventInvoker";
  23. console.visible = true;
  24. console.closeButton.visible = false;
  25. // Show OS mouse cursor
  26. input.mouseVisible = true;
  27. // Set the mouse mode to use in the sample
  28. SampleInitMouseMode(MM_FREE);
  29. // Open the operating system console window (for stdin / stdout) if not open yet
  30. // Do not open in fullscreen, as this would cause constant device loss
  31. if (!graphics.fullscreen)
  32. OpenConsoleWindow();
  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(DBAPI == DBAPI_ODBC ? "Driver=SQLite3;Database=:memory:" : "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.\n"
  52. "All the tables and their data will be lost after exiting the demo.\n"
  53. "Enter a valid SQL statement in the console input and press Enter to execute.\n"
  54. "Enter 'get/set maxrows [number]' to get/set the maximum rows to be printed out.\n"
  55. "Enter 'get/set connstr [string]' to get/set the database connection string and establish a new connection to it.\n"
  56. "Enter 'quit' or 'exit' to exit the demo.\n"
  57. "For example:\n ");
  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. }
  63. void HandleConsoleCommand(StringHash eventType, VariantMap& eventData)
  64. {
  65. if (eventData["Id"].GetString() == "ScriptEventInvoker")
  66. HandleInput(eventData["Command"].GetString());
  67. }
  68. void HandleUpdate(StringHash eventType, VariantMap& eventData)
  69. {
  70. // Check if there is input from stdin
  71. String input = GetConsoleInput();
  72. if (input.length > 0)
  73. HandleInput(input);
  74. }
  75. void HandleEscKeyDown(StringHash eventType, VariantMap& eventData)
  76. {
  77. // Unlike the other samples, exiting the engine when ESC is pressed instead of just closing the console
  78. if (eventData["Key"].GetInt() == KEY_ESCAPE)
  79. engine.Exit();
  80. }
  81. void HandleDbCursor(StringHash eventType, VariantMap& eventData)
  82. {
  83. // In a real application the P_SQL can be used to do the logic branching in a shared event handler
  84. // However, this is not required in this sample demo
  85. uint numCols = eventData["NumCols"].GetUInt();
  86. Array<Variant>@ colValues = eventData["ColValues"].GetVariantVector();
  87. Array<String>@ colHeaders = eventData["ColHeaders"].GetStringVector();
  88. // In this sample demo we just use db cursor to dump each row immediately so we can filter out the row to conserve memory
  89. // In a real application this can be used to perform the client-side filtering logic
  90. eventData["Filter"] = true;
  91. // In this sample demo we abort the further cursor movement when maximum rows being dumped has been reached
  92. eventData["Abort"] = ++row >= maxRows;
  93. for (uint i = 0; i < numCols; ++i)
  94. Print("Row #" + row + ": " + colHeaders[i] + " = " + colValues[i].ToString());
  95. }
  96. void HandleInput(const String&in input)
  97. {
  98. // Echo input string to stdout
  99. Print(input);
  100. row = 0;
  101. if (input == "quit" || input == "exit")
  102. engine.Exit();
  103. else if (input.StartsWith("set") || input.StartsWith("get"))
  104. {
  105. // We expect a key/value pair for 'set' command
  106. Array<String> tokens = input.Substring(3).Split(' ');
  107. String setting = tokens.length > 0 ? tokens[0] : "";
  108. if (input.StartsWith("set") && tokens.length > 1)
  109. {
  110. if (setting == "maxrows")
  111. maxRows = Max(tokens[1].ToUInt(), 1);
  112. else if (setting == "connstr") {
  113. String newConnectionString(input.Substring(input.Find(" ", input.Find("connstr")) + 1));
  114. DbConnection@ newConnection = database.Connect(newConnectionString);
  115. if (newConnection !is null)
  116. {
  117. database.Disconnect(connection);
  118. connection = newConnection;
  119. }
  120. }
  121. }
  122. if (tokens.length > 0)
  123. {
  124. if (setting == "maxrows")
  125. Print("maximum rows is set to " + maxRows);
  126. else if (setting == "connstr")
  127. Print("connection string is set to " + connection.connectionString);
  128. else
  129. Print("Unrecognized setting: " + setting);
  130. }
  131. else
  132. Print("Missing setting paramater. Recognized settings are: maxrows, connstr");
  133. }
  134. else
  135. {
  136. // In this sample demo we use the dbCursor event to loop through each row as it is being fetched
  137. // Regardless of this event is being used or not, all the fetched rows will be made available in the DbResult object,
  138. // unless the dbCursor event handler has instructed to filter out the fetched row from the final result
  139. DbResult result = connection.Execute(input, true);
  140. // Number of affected rows is only meaningful for DML statements like insert/update/delete
  141. if (result.numAffectedRows != -1)
  142. Print("Number of affected rows: " + result.numAffectedRows);
  143. }
  144. Print(" ");
  145. }
  146. // Create XML patch instructions for screen joystick layout specific to this sample app
  147. String patchInstructions =
  148. "<patch>" +
  149. " <add sel=\"/element/element[./attribute[@name='Name' and @value='Button2']]\">" +
  150. " <attribute name=\"Is Visible\" value=\"false\" />" +
  151. " </add>" +
  152. " <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" +
  153. " <attribute name=\"Is Visible\" value=\"false\" />" +
  154. " </add>" +
  155. "</patch>";