2shady4u / godot-sqlite

GDExtension wrapper for SQLite (Godot 4.x+)
MIT License
906 stars 80 forks source link

Value returned from select_rows is the same reference? #38

Closed hagabooga closed 3 years ago

hagabooga commented 3 years ago

Spent an hour wondering why my value returned from select_rows was being modified incorrectly and realized if I called select rows again in the same function it changes the previously stored variable or some undefined behavior.

Example:

var data = db.select_rows("players")
print(data) # [{"id":0, "health"100}, {"id":1, "health"100}]
for x  in data:
    x.item = db.select_rows("item") 
    # db.select_rows("item") should return [{"name": sword}]
    # this changes variable 'data' to be equal to this function call completely and x.item is no where to be found
    # basically data = [{"name": sword}] now

I don't know whether or not this is intended or I'm missing something but maybe there should be something on the docs about it?

To fix this I need to duplicate data.

data = data.duplicate()
2shady4u commented 3 years ago

This is due to the fact that Godot dictionaries and arrays are passed by reference. Basically when you call the .select_rows() function again, the data values are overwritten since it is the exact same reference. https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/gdscript_basics.html#built-in-types

As you mention, You'll need to duplicate the data to fix this. (Possibly you'll also have to set the deep-value to True)

Since this is Godot's intended behaviour, I don't think anything needs to be fixed per se?

hagabooga commented 3 years ago

but why does select_rows return the same reference?

2shady4u commented 3 years ago

For two main reasons:

  1. The duplicate()-function hasn't been properly implemented yet in godot-cpp, so I can't call it myself in the C++ code 🤷‍♂️ I would have to use my own (inferior = slower) implementation.
  2. Passing the data by reference speeds up the select_rows()-function when you are selecting 1000+ rows (or any larger amount than 2) since you don't have to copy every field by value.

Or if you are asking this question in a more 'How is this implemented in C++?' way:

hagabooga commented 3 years ago

select_rows returning query_result makes sense now. Thanks for the quick reply.