Check if the new table has been created

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
25 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Check if the new table has been created

Igor Korot
 Hi,
Is there a C API which checks if the new table has been created?

Thank you.
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

wmertens
you can query the table with
https://www.sqlite.org/pragma.html#pragma_table_info

On Tue, Jun 19, 2018, 8:26 PM Igor Korot <[hidden email]> wrote:

>  Hi,
> Is there a C API which checks if the new table has been created?
>
> Thank you.
> _______________________________________________
> sqlite-users mailing list
> [hidden email]
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Igor Korot
Hi, Wout,

On Tue, Jun 19, 2018 at 1:31 PM, Wout Mertens <[hidden email]> wrote:
> you can query the table with
> https://www.sqlite.org/pragma.html#pragma_table_info

Let me give you a scenario:

1. My application connects to the database and performs some
operations (using C API).
2. During the application run, someone started sqlite3, connects to
the database and creates a
brand new table.
3. My application will need to pick up the newly created table and continue.

Is it easily possible?

There is a sqlite3_*_hook() family of functions, but it looks like
they won't help with sqlite_master.

Is there a different way?

Thank you.

>
> On Tue, Jun 19, 2018, 8:26 PM Igor Korot <[hidden email]> wrote:
>
>>  Hi,
>> Is there a C API which checks if the new table has been created?
>>
>> Thank you.
>> _______________________________________________
>> sqlite-users mailing list
>> [hidden email]
>> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>>
> _______________________________________________
> sqlite-users mailing list
> [hidden email]
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Richard Hipp-3
On 6/19/18, Igor Korot <[hidden email]> wrote:

> Hi, Wout,
>
> On Tue, Jun 19, 2018 at 1:31 PM, Wout Mertens <[hidden email]>
> wrote:
>> you can query the table with
>> https://www.sqlite.org/pragma.html#pragma_table_info
>
> Let me give you a scenario:
>
> 1. My application connects to the database and performs some
> operations (using C API).
> 2. During the application run, someone started sqlite3, connects to
> the database and creates a
> brand new table.
> 3. My application will need to pick up the newly created table and continue.
>
> Is it easily possible?
>
> There is a sqlite3_*_hook() family of functions, but it looks like
> they won't help with sqlite_master.
>
> Is there a different way?

Poll the PRAGMA schema_version value and watch for changes.
--
D. Richard Hipp
[hidden email]
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Abroży Nieprzełoży
In reply to this post by Igor Korot
afaik there is no such api.
You need to periodically check if something changed.

Run
    pragma schema_version;
to get current schema version.
If it changes then run
    select name from sqlite_master where type='table' and name not
like 'sqlite_%';
to get the list of table names and compare this list with one you've
got previously.


2018-06-19 20:42 GMT+02:00, Igor Korot <[hidden email]>:

> Hi, Wout,
>
> On Tue, Jun 19, 2018 at 1:31 PM, Wout Mertens <[hidden email]>
> wrote:
>> you can query the table with
>> https://www.sqlite.org/pragma.html#pragma_table_info
>
> Let me give you a scenario:
>
> 1. My application connects to the database and performs some
> operations (using C API).
> 2. During the application run, someone started sqlite3, connects to
> the database and creates a
> brand new table.
> 3. My application will need to pick up the newly created table and continue.
>
> Is it easily possible?
>
> There is a sqlite3_*_hook() family of functions, but it looks like
> they won't help with sqlite_master.
>
> Is there a different way?
>
> Thank you.
>
>>
>> On Tue, Jun 19, 2018, 8:26 PM Igor Korot <[hidden email]> wrote:
>>
>>>  Hi,
>>> Is there a C API which checks if the new table has been created?
>>>
>>> Thank you.
>>> _______________________________________________
>>> sqlite-users mailing list
>>> [hidden email]
>>> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>>>
>> _______________________________________________
>> sqlite-users mailing list
>> [hidden email]
>> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
> _______________________________________________
> sqlite-users mailing list
> [hidden email]
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Simon Slavin-3
In reply to this post by Richard Hipp-3


On 19 Jun 2018, at 7:56pm, Richard Hipp <[hidden email]> wrote:

> Poll the PRAGMA schema_version value and watch for changes.

This is the best way.  (I'm hardly likely to argue with DRH, am I ?)

However, it's a terrible way to communicate using a database system.  If you want two connections to communicate have one connection create a new row in an existing table, which the other can query.

Simon.
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

R Smith-2
In reply to this post by Igor Korot

On 2018/06/19 8:26 PM, Igor Korot wrote:
>   Hi,
> Is there a C API which checks if the new table has been created?

We could break this down into a few separate questions:

1 - Is there a C API that can return SQL query answers?
YES there is.

2 - Can I ask this API in SQL if the Schema changed, since
altering/adding/deleting a table involves schema changes?
YES you can. [I see this pragma schema_version is already mentioned in
other replies]

3 - Once I know the schema changed, can I ask for a list of tables to
compare to my predefined/pre-loaded/cached list to know WHICH tables
were changed/added/deleted?
YES you can: [pragma table_info]

4 - Can I use all of the above to update my cached table list and
refresh interfaces as needed?
Well, technically that's up to your mad skillz as a programmer, but
having seen your posts many times before, I'm going to bet on: YES, you can.

5 - Is there a C-API that does all of the above in one go for me?
I'm afraid NOT.


Good luck!
Ryan

_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Igor Korot
Hi, Ryan,

On Tue, Jun 19, 2018 at 3:22 PM, R Smith <[hidden email]> wrote:

>
> On 2018/06/19 8:26 PM, Igor Korot wrote:
>>
>>   Hi,
>> Is there a C API which checks if the new table has been created?
>
>
> We could break this down into a few separate questions:
>
> 1 - Is there a C API that can return SQL query answers?
> YES there is.
>
> 2 - Can I ask this API in SQL if the Schema changed, since
> altering/adding/deleting a table involves schema changes?
> YES you can. [I see this pragma schema_version is already mentioned in other
> replies]
>
> 3 - Once I know the schema changed, can I ask for a list of tables to
> compare to my predefined/pre-loaded/cached list to know WHICH tables were
> changed/added/deleted?
> YES you can: [pragma table_info]
>
> 4 - Can I use all of the above to update my cached table list and refresh
> interfaces as needed?
> Well, technically that's up to your mad skillz as a programmer, but having
> seen your posts many times before, I'm going to bet on: YES, you can.
>
> 5 - Is there a C-API that does all of the above in one go for me?
> I'm afraid NOT.

Thank you.
This post summarizes it all.

I'll follow thru when I get back home.


>
>
> Good luck!
> Ryan
>
>
> _______________________________________________
> sqlite-users mailing list
> [hidden email]
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Igor Korot
Hi, guys,

On Tue, Jun 19, 2018 at 4:37 PM, Igor Korot <[hidden email]> wrote:

> Hi, Ryan,
>
> On Tue, Jun 19, 2018 at 3:22 PM, R Smith <[hidden email]> wrote:
>>
>> On 2018/06/19 8:26 PM, Igor Korot wrote:
>>>
>>>   Hi,
>>> Is there a C API which checks if the new table has been created?
>>
>>
>> We could break this down into a few separate questions:
>>
>> 1 - Is there a C API that can return SQL query answers?
>> YES there is.
>>
>> 2 - Can I ask this API in SQL if the Schema changed, since
>> altering/adding/deleting a table involves schema changes?
>> YES you can. [I see this pragma schema_version is already mentioned in other
>> replies]
>>
>> 3 - Once I know the schema changed, can I ask for a list of tables to
>> compare to my predefined/pre-loaded/cached list to know WHICH tables were
>> changed/added/deleted?
>> YES you can: [pragma table_info]
>>
>> 4 - Can I use all of the above to update my cached table list and refresh
>> interfaces as needed?
>> Well, technically that's up to your mad skillz as a programmer, but having
>> seen your posts many times before, I'm going to bet on: YES, you can.
>>
>> 5 - Is there a C-API that does all of the above in one go for me?
>> I'm afraid NOT.
>
> Thank you.
> This post summarizes it all.
>
> I'll follow thru when I get back home.

One more question:

I presume I should call PRAGMA schema_version right after connection
has been made,
cache the value returned and then create a secondary thread which will
call this query continuously.

Am I right?

Thank you.

>
>
>>
>>
>> Good luck!
>> Ryan
>>
>>
>> _______________________________________________
>> sqlite-users mailing list
>> [hidden email]
>> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Peter Johnson
In reply to this post by Richard Hipp-3
Is it possible to create a trigger on sqlite_master which calls a
user-defined function AFTER INSERT?

That would avoid having to poll, but it'd still allow the application to be
notified when the schema changed.

On 19 June 2018 at 20:56, Richard Hipp <[hidden email]> wrote:

> On 6/19/18, Igor Korot <[hidden email]> wrote:
> > Hi, Wout,
> >
> > On Tue, Jun 19, 2018 at 1:31 PM, Wout Mertens <[hidden email]>
> > wrote:
> >> you can query the table with
> >> https://www.sqlite.org/pragma.html#pragma_table_info
> >
> > Let me give you a scenario:
> >
> > 1. My application connects to the database and performs some
> > operations (using C API).
> > 2. During the application run, someone started sqlite3, connects to
> > the database and creates a
> > brand new table.
> > 3. My application will need to pick up the newly created table and
> continue.
> >
> > Is it easily possible?
> >
> > There is a sqlite3_*_hook() family of functions, but it looks like
> > they won't help with sqlite_master.
> >
> > Is there a different way?
>
> Poll the PRAGMA schema_version value and watch for changes.
> --
> D. Richard Hipp
> [hidden email]
> _______________________________________________
> sqlite-users mailing list
> [hidden email]
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Abroży Nieprzełoży
But that trigger would be executed in a context of a process modifying
the database.

2018-06-20 8:24 GMT+02:00, Peter Johnson <[hidden email]>:

> Is it possible to create a trigger on sqlite_master which calls a
> user-defined function AFTER INSERT?
>
> That would avoid having to poll, but it'd still allow the application to be
> notified when the schema changed.
>
> On 19 June 2018 at 20:56, Richard Hipp <[hidden email]> wrote:
>
>> On 6/19/18, Igor Korot <[hidden email]> wrote:
>> > Hi, Wout,
>> >
>> > On Tue, Jun 19, 2018 at 1:31 PM, Wout Mertens <[hidden email]>
>> > wrote:
>> >> you can query the table with
>> >> https://www.sqlite.org/pragma.html#pragma_table_info
>> >
>> > Let me give you a scenario:
>> >
>> > 1. My application connects to the database and performs some
>> > operations (using C API).
>> > 2. During the application run, someone started sqlite3, connects to
>> > the database and creates a
>> > brand new table.
>> > 3. My application will need to pick up the newly created table and
>> continue.
>> >
>> > Is it easily possible?
>> >
>> > There is a sqlite3_*_hook() family of functions, but it looks like
>> > they won't help with sqlite_master.
>> >
>> > Is there a different way?
>>
>> Poll the PRAGMA schema_version value and watch for changes.
>> --
>> D. Richard Hipp
>> [hidden email]
>> _______________________________________________
>> sqlite-users mailing list
>> [hidden email]
>> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>>
> _______________________________________________
> sqlite-users mailing list
> [hidden email]
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

R Smith
In reply to this post by Igor Korot

On 2018/06/20 7:05 AM, Igor Korot wrote:
> One more question:
>
> I presume I should call PRAGMA schema_version right after connection
> has been made,
> cache the value returned and then create a secondary thread which will
> call this query continuously.
>
> Am I right?

That is up to you, but what you need to know is basically that every
time the schema is changed for whatever reason (via standard methods in
the API [1]), there is a schema-version counter that gets incremented
[2], and this counter value is returned when you query pragma
schema_version.

That means that that query will return the same integer value
consistently, across database connections, until the schema changes, and
from then on a new incremented value is returned, so everything that's
been paying attention to the value before will know the value is now new
and so the schema has changed.  (One could even deduce how many times it
changed from the value, though that is not typically useful information).


Cheers!
Ryan

[1] There is a way to circumvent the standard methods by setting a
pragma to make the schema writable - in which case I'm not sure if the
schema_version counter still gets updated - but either way, that should
never happen during normal operation.

[2] The counter is also accessible via reading the SQLite file header if
you deal directly with file-io in stead of the normal API or perhaps
have a system that monitors sqlite files rather than a specific
connection (just search "file header" in the SQLite site), but then you
have to deal with file locking, access error handling etc. Best is to
just query the pragma.
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

R Smith-2
In reply to this post by Igor Korot
--Re-posted from correct address - apologies if this comes through twice--

On 2018/06/20 7:05 AM, Igor Korot wrote:
> One more question:
>
> I presume I should call PRAGMA schema_version right after connection
> has been made,
> cache the value returned and then create a secondary thread which will
> call this query continuously.
>
> Am I right?

That is up to you, but what you need to know is basically that every
time the schema is changed for whatever reason (via standard methods in
the API [1]), there is a schema-version counter that gets incremented
[2], and this counter value is returned when you query pragma
schema_version.

That means that that query will return the same integer value
consistently, across database connections, until the schema changes, and
from then on a new incremented value is returned, so everything that's
been paying attention to the value before will know the value is now new
and so the schema has changed.  (One could even deduce how many times it
changed from the value, though that is not typically useful information).


Cheers!
Ryan

[1] There is a way to circumvent the standard methods by setting a
pragma to make the schema writable - in which case I'm not sure if the
schema_version counter still gets updated - but either way, that should
never happen during normal operation.

[2] The counter is also accessible via reading the SQLite file header if
you deal directly with file-io in stead of the normal API or perhaps
have a system that monitors sqlite files rather than a specific
connection (just search "file header" in the SQLite site), but then you
have to deal with file locking, access error handling etc. Best is to
just query the pragma.


_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Simon Slavin-3
In reply to this post by Peter Johnson
On 20 Jun 2018, at 7:24am, Peter Johnson <[hidden email]> wrote:

> Is it possible to create a trigger on sqlite_master which calls a
> user-defined function AFTER INSERT?

No.  sqlite_master is modified using internal methods, not using an INSERT command.  TRIGGERs on it won't work.

Simon.
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Simon Slavin-3
On 20 Jun 2018, at 12:29pm, Simon Slavin <[hidden email]> wrote:

> On 20 Jun 2018, at 7:24am, Peter Johnson <[hidden email]> wrote:
>
>> Is it possible to create a trigger on sqlite_master which calls a
>> user-defined function AFTER INSERT?
>
> No.  sqlite_master is modified using internal methods, not using an INSERT command.  TRIGGERs on it won't work.

Are you not able to modify the program which adds so that it uses an existing table instead ?

Simon.
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Igor Korot
Hi, guys,
I put in this code:

                    if( sqlite3_prepare_v2( m_db, "PRAGMA
schema_version", NULL, &stmt, NULL ) == SQLITE_OK )
                    {
                        if( ( res = sqlite3_step( stmt ) ) == SQLITE_OK )
                        {
                            m_schema = sqlite3_column_int( stmt, 0 );
                            pimpl->m_dbName = sqlite_pimpl->m_catalog;
                        }
                        else
                        {
                        }
                    }
                    else
                    {
                    }

The call to sqlite3_step() failed - it returned 21.

Anyone sees any issues?

Thank you.

On Wed, Jun 20, 2018 at 6:32 AM, Simon Slavin <[hidden email]> wrote:

> On 20 Jun 2018, at 12:29pm, Simon Slavin <[hidden email]> wrote:
>
>> On 20 Jun 2018, at 7:24am, Peter Johnson <[hidden email]> wrote:
>>
>>> Is it possible to create a trigger on sqlite_master which calls a
>>> user-defined function AFTER INSERT?
>>
>> No.  sqlite_master is modified using internal methods, not using an INSERT command.  TRIGGERs on it won't work.
>
> Are you not able to modify the program which adds so that it uses an existing table instead ?
>
> Simon.
> _______________________________________________
> sqlite-users mailing list
> [hidden email]
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Richard Hipp-3
On 6/20/18, Igor Korot <[hidden email]> wrote:
>                         if( ( res = sqlite3_step( stmt ) ) == SQLITE_OK )

sqlite3_step() returns SQLITE_ROW when it has data, not SQLITE_OK.

--
D. Richard Hipp
[hidden email]
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

Igor Korot
Richard,

On Wed, Jun 20, 2018 at 8:17 PM, Richard Hipp <[hidden email]> wrote:
> On 6/20/18, Igor Korot <[hidden email]> wrote:
>>                         if( ( res = sqlite3_step( stmt ) ) == SQLITE_OK )
>
> sqlite3_step() returns SQLITE_ROW when it has data, not SQLITE_OK.

But SQLITE_ROW value is not 21 - its 101.

Thank you.

>
> --
> D. Richard Hipp
> [hidden email]
> _______________________________________________
> sqlite-users mailing list
> [hidden email]
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

David Burgess-2
;

On Thu, Jun 21, 2018 at 12:03 PM, Igor Korot <[hidden email]> wrote:

> Richard,
>
> On Wed, Jun 20, 2018 at 8:17 PM, Richard Hipp <[hidden email]> wrote:
>> On 6/20/18, Igor Korot <[hidden email]> wrote:
>>>                         if( ( res = sqlite3_step( stmt ) ) == SQLITE_OK )
>>
>> sqlite3_step() returns SQLITE_ROW when it has data, not SQLITE_OK.
>
> But SQLITE_ROW value is not 21 - its 101.
>
> Thank you.
>
>>
>> --
>> D. Richard Hipp
>> [hidden email]
>> _______________________________________________
>> sqlite-users mailing list
>> [hidden email]
>> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
> _______________________________________________
> sqlite-users mailing list
> [hidden email]
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Reply | Threaded
Open this post in threaded view
|

Re: Check if the new table has been created

David Empson
In reply to this post by Igor Korot
Apart from the SQLITE_OK vs SQLITE_ROW/DONE check on the sqlite3_step() call mentioned already, you also have the third parameter to sqlite_prepare_v2() wrong: nByte = NULL will translate to nByte = 0 which is documented as “no prepared statement is generated”. Therefore stmt is not valid and sqlite3_step() returns SQLITE_MISUSE.

Try -1 instead of NULL.

> On 21/06/2018, at 12:44 PM, Igor Korot <[hidden email]> wrote:
>
> Hi, guys,
> I put in this code:
>
>                    if( sqlite3_prepare_v2( m_db, "PRAGMA
> schema_version", NULL, &stmt, NULL ) == SQLITE_OK )
>                    {
>                        if( ( res = sqlite3_step( stmt ) ) == SQLITE_OK )
>                        {
>                            m_schema = sqlite3_column_int( stmt, 0 );
>                            pimpl->m_dbName = sqlite_pimpl->m_catalog;
>                        }
>                        else
>                        {
>                        }
>                    }
>                    else
>                    {
>                    }
>
> The call to sqlite3_step() failed - it returned 21.
>
> Anyone sees any issues?
>
> Thank you.


_______________________________________________
sqlite-users mailing list
[hidden email]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
12